I am currently running a website, i use a control that inherits from ITemplate to wrap all my usercontrols in.
basically what it is, is a table with a nice border, and i am able to dump anything in there, so if i change the container template, all the containers accross the site changes...
I am now in the process of rebuilding the entire application using MVC 2, does anyone know of a way i can achieve the same "Container" like template in MVC?
There would be several ways to do this in MVC, but I would probably suggest using a custom HTML Helper.
There is an example on how to implement something similar in this post. Look for the section titled "Creating a DataGrid Helper" in that post for more information. I think you will be able to adapt that example to fit your purpose.
I managed Thanx here is an example:
public static class Block
{
public static BlockHelper BeginBlock(this System.Web.Mvc.HtmlHelper content, string title)
{
return new BlockHelper(content, title);
}
}
public class BlockHelper : IDisposable
{
private readonly HtmlHelper _content;
private readonly HtmlHelper _title;
public BlockHelper(System.Web.Mvc.HtmlHelper content, string title)
{
_content = content;
StringBuilder sb = new StringBuilder();
sb.Append("<div>");
sb.Append("<div><h1>" + title + "</h1></div>");
_content.ViewContext.Writer.Write(sb.ToString());
}
public void Dispose()
{
StringBuilder sb = new StringBuilder();
sb.Append("</div>");
_content.ViewContext.Writer.Write(sb.ToString());
}
}
and then i basically uses it as follows:
<% using( Html.BeginBlock("TITLE>CONTENT GOES HERE<%}%>
Related
I'd like to create a ViewHelper to localize my ASP.NET MVC application. Something like this:
public class Translator
{
private readonly ITranslationRepository _repo;
public Translator(ITranslationRepository repo)
{
_repo = repo;
}
public static string Translate(TranslationEnum translationEnum)
{
return _repo.GetTranslation(translationEnum, Session.LanguageId);
}
}
Usage in a (Razor) View looks like this:
<p>#Translator.Translate(TranslationEnum.WelcomeMessage)</p>
Now the problem is of course, I cannot make the Translate method static, because I need to access the instance variable _repo.
How can I inject the repository into a ViewHelper so I can use it in a View like above?
The responsibility of the view is just to transform the data that comes back from the controller to a HTML structure. Views are hard (to impossible) to test automatically, so best is to keep them as dumb as possible.
Instead of using the Translator in your view, inject it into your controller and let the controller call the Translator. This solves a range of problems:
It keeps the view simple.
It improves maintainability.
It improves testability.
It improves the verifiability of your object graphs (because you don't fall back on static method calls or the Service Locator anti-pattern).
Long story short, add a property to the controller's view model and return that to the view. Example:
public class HomeController : Controller {
private readonly ITranslator translator;
public HomeController(ITranslator translator) {
this.translator = translator
}
public ActionResult Index() {
this.View(new HomeViewModel {
WelcomeMessage = this.translator.Translate(TranslationEnum.WelcomeMessage)
});
}
}
And your view can look as follows:
#model HomeViewModel
<p>#Model.WelcomeMessage</p>
first of all, the intention of your design is wrong because it violates the single responsibility principal. Why is a translator dependent on repository?
secondly, why do you need a translator, you can use asp.net globalization?
click me We should not reinvent the wheel.
thirdly, all the html helpers are extension methods which have to be static.
so my suggestion is if you have to use translator, please refactor the Translator class, decouple the repository from it then create a extension methods from there.
or you can use globalization, it sounds horrible to start with but trust me it's not as hard as it looks.
public class Translator
{
private static ITranslationRepository _repo;
public static ITranslationRepository Repo
{
get { /*check null here before return*/ return _repo; } set { _repo = Repo; }
}
public Translator()
{
}
public static string Translate(TranslationEnum translationEnum)
{
return _repo.GetTranslation(translationEnum, Session.LanguageId);
}
}
I have a TreeView, wish is used to display some hierarchy. Also, I have some behaviors implemented, such as if the collapsed nodes will be opened when the parent is checked, or if it's lazy loading or will load everything automatically. But I don't want to let these behaviors hard coded. I want to create a customizable control. Something like Telerik Kendo UI does. They have a control developed, that can be used like this:
#(Html.Kendo().MaskedTextBox()
.Name("phone_number")
.Mask("(999) 000-0000")
.Value("555 123 4567")
)
Notice that you can pass some options to it.
Also, I want to be able to pass the name of the action that will populate my TreeView using async. So, if I use this component at, for example, mysite/myController/indexAction, I want to pass a name of the action who will populate my component asynchronous. Let's exemplify. I want something like this:
#(Html.Foo().HierarchyView()
.Name("myTree")
.AllowCheckBoxes(true)
.PopulateChildrenOnCheck(true)
.Async("GetChildrenAsync")
)
So, I can implement at myController an action
string GetChildrenAsync(int idKey) {
var nodes = new List<HierarchViewNodes>();
(...) //implementation to populate the children nodes
return JsonConvert.SerializeObject(nodes);
}
So, it would be an start for my customizable control. Of course I can extend it a lot.
I've searched and learned about RenderPartial and RenderAction, but I can't figure out yet how I can fully use it to make really reusable controls like the one I explained.
You might want to take a look at making some custom HTML helpers. For example, yours might look something like this:
public static MvcHtmlString MyTreeView(this HtmlHelper html, params...){
var myHtmlContent = ....;
// .. implement your functionality and generate the html to put in your view
return MvcHtmlString.Create(myHtmlContent);
}
and you could use it in your Razor view like this:
<div>#Html.MyTreeView(params...)</div>
That is a very simple example, but hopefully it puts you on the right track.
I'd suggest some HTML extensions, as rwisch45 said, but protected (and organized) within a separate "sub-helper", like Kendo and DevExpress:
public static class HtmlExtensions
{
public static static MyCustomHelper CustomHelper(this HtmlHelper htmlHelper)
{
return new MyCustomHelper(htmlHelper);
}
}
public class MyCustomHelper
{
HtmlHelper _HtmlHelper;
public MyCustomHelper(HtmlHelper htmlHelper) { _HtmlHelper = htmlHelper; }
public MvcHtmlString WriteSomethingInteresting(string value)
{ return new MvcHtmlString(value); }
public MyCustomGrid CreateMyGrid(object gridOptions)
{
// I won't show now how to transform dynamic into type.
// You can find that on SO quite easy.
var typedOptions = TransformDynamicIntoClass<GridOptions>(gridOptions);
return new MyCustomGrid(typedOptions);
}
}
public class MyCustomGrid : IHtmlString
{
public string ToHtmlString()
{
// Return your grid as an HTML object!
}
}
This way you'll have:
#Html.CustomHelper().MyCustomGrid(new { Option1 = "", Option2 = "", ...... });
You may, however, play a little with IDisposable, to have something like:
#using(Html.CustomHelper().MyCustomGrid(....))
{
// Dunno what could come here for a grid (poor sample) but maybe for a pane helper?
}
I like the idea of Steven Sanderson's Partial Requests in http://blog.stevensanderson.com/2008/10/14/partial-requests-in-aspnet-mvc/ and I'm trying to get it to work with Razor pages. Unfortunately it writes it to the top of the page, instead of where I actually want it to be in the document. I'm guessing the problem is similar to the one answered here: ASP.Net MVC 3 Razor Response.Write position but I don't know how to get around it.
Can anyone supply me with a workaround? Failing that, is there simply another good technique for rendering the contents of another action in a view, without that view having to know about the action?
Yes, it is possible.
As I'm sure you're now aware the Razor view engine writes to temporary buffers before writing to the response stream, which is why when you invoke another action the markup gets written to the response out of order.
The workaround that I've used in the past is to temporarily redirect any writes to the response to a MemoryStream while you are trying to render another action, and then creating a MvcHtmlString from the contents of the MemoryStream.
So something like:
public class HttpResonseCapture : IDisposable
{
private readonly MemoryStream _stream = new MemoryStream();
private readonly Stream _originalStream;
private readonly HttpContextBase _httpContext;
public HttpResponseCapture(HttpContextBase httpContext)
{
_httpContext = httpContext;
_originalStream = httpContext.Response.OutputStream;
httpContext.Response.OutputStream = _stream;
}
public MvcHtmlString ToHtmlString()
{
return MvcHtmlString.Create(Encoding.Unicode.GetString(_stream.ToArray()));
}
public void Dispose()
{
_httpContext.Response.OutputStream = _originalStream;
_stream.Dispose();
}
}
Can be used like so:
using (var responseCapture = new HttpResponseCapture(httpContext))
{
// Call other action here
var result = responseCapture.ToHtmlString();
}
So for example in the code behind of a web form aspx page I would like to be able to do things like
string textBoxHtml = Html.TextBox("MyTextBox");
Is this possible?
Is the source code available to fork for webforms?
Possible? Yes.
The entire MVC source is available at:
http://www.microsoft.com/downloads/details.aspx?FamilyID=53289097-73ce-43bf-b6a6-35e00103cb4b&displaylang=en
Good luck!
You'll quickly find that pulling bits of code out of MVC is like only wanting a banana and getting the gorilla holding it. ;)
Here's something that is working for me so far.
public static class PageCommon
{
public static System.Web.Mvc.UrlHelper GetUrlHelper(this System.Web.UI.Control c)
{
var helper = new System.Web.Mvc.UrlHelper(c.Page.Request.RequestContext);
return helper;
}
class ViewDataBag : IViewDataContainer
{
ViewDataDictionary vdd = new ViewDataDictionary();
public ViewDataDictionary ViewData
{
get
{
return vdd;
}
set
{
vdd = value;
}
}
}
public static System.Web.Mvc.HtmlHelper GetHtmlHelper(this System.Web.UI.Control c)
{
IViewDataContainer x;
var v = new System.Web.Mvc.ViewContext();
var helper = new System.Web.Mvc.HtmlHelper(v, new ViewDataBag());
return helper;
}
I like the Validation Application Block from the Enterprise Library :-)
Now i would like to use the DataAnnotations in Winforms, as we use asp.net Dynamic Data as well. So that we have common technologies over the whole company.
And also the Data Annotations should be easier to use.
How can I do something similiar in Winforms like Stephen Walter did within asp.net MVC?
I adapted a solution found at http://blog.codeville.net/category/validation/page/2/
public class DataValidator
{
public class ErrorInfo
{
public ErrorInfo(string property, string message)
{
this.Property = property;
this.Message = message;
}
public string Message;
public string Property;
}
public static IEnumerable<ErrorInfo> Validate(object instance)
{
return from prop in instance.GetType().GetProperties()
from attribute in prop.GetCustomAttributes(typeof(ValidationAttribute), true).OfType<ValidationAttribute>()
where !attribute.IsValid(prop.GetValue(instance, null))
select new ErrorInfo(prop.Name, attribute.FormatErrorMessage(string.Empty));
}
}
This would allow you to use the following code to validate any object using the following syntax:
var errors = DataValidator.Validate(obj);
if (errors.Any()) throw new ValidationException();