MVC3 View Inheritance not possible? - asp.net-mvc-3

I want to create an abstract base view (with lots of virtual methods with cshtml)
and then create a derived view that optionally overrides these methods to customise the view:
for example:
override void Header(string title) {
<div class="massive">#title</div>
}
How can this be achieved with razor?
(doesn't everybody want/need to do this?)

I believe you would be better off using Helper methods than trying for an inheritance model on views. Use Scott Gu's blog for an introduction:
http://weblogs.asp.net/scottgu/archive/2011/05/12/asp-net-mvc-3-and-the-helper-syntax-within-razor.aspx
http://www.asp.net/mvc/tutorials/creating-custom-html-helpers-cs

It doesn't quite work like that out of the box, although I'm sure with some effort you could get that to work.
Instead, you create Layouts with defined Sections and then derive other Layouts from those adding new sections if you need to. Then, a view will declare which layout it is using via
#{
Layout = "_Layout.cshtml" // app relative path to layout
}
and can provide markup for any sections as needed using
#section SectionName {
<p>I'm markup to go into a section in the layout this view is using</p>
}
You can pass data via ViewData and/or ViewBag, so you could use them to pass delegates if you wanted to do that.
Alternatively, you might decide add extension methods to HtmlHelper, UrlHelper or even create a WebViewPage derived from System.Web.Mvc.WebViewPage and add any additional properties/methods onto your derived type then set it as the pageBaseType in the <system.web.webPages.razor> in the web.config used by the views.

Simply use sections and layouts. You would define a layout containing some default contents into sections which could be overridden in child views. You could use the IsSectionDefined method in the layout to test whether a child view overrides this section and if not provide default content.

The cleanest way I found is to use a #helper declared in App_Code
which takes delegates as arguments:
#helper Example(Func<int, HelperResult> fn1, Func<int, HelperResult> fn2) {
<div>#fn1(100)</div>
<div>#fn2(200)</div>
}
and then create a view with helper functions:
#helper Custom1(int x) { <span class="small">#x</span> }
#helper Custom2(int x) { <span class="big">#x</span> }
and then invoke shared helper like this:
#Example(Custom1, Custom2)
and, if required, the shared helper can implement a default behaviour if the delegate is null
this is much messier than simply implementing a derived view with a few overriden virtual helpers - but at least it works, is strongly typed, and doesn't use dynamic

Related

Ember.js: How can I decouple my views from my controllers?

I'm trying to restructure tightly coupled portions of an ember.js app, particularly views and templates to controllers.
All the examples I've seen bind views directly to controllers in the view's class definition, or by pass the (global) controller path to the view in the template itself.
The TargetActionSupport mixin (DelegateSupport in sproutcore, I think) seems like a good candidate, but would still require the target (controller) and action to be set in the template itself.
Ideally, I would like to instantiate my views in my controller (somehow), set targets and actions, but also set presentational variables in my templates (ex: static classes, id), but I'm not sure how to accomplish something this, or whether it's the right approach.
You can programmatically instantiate views and insert them into the DOM wherever you'd like:
var view = Ember.View.create();
view.appendTo('#someElement');
If you want to eliminate global binding paths, you can pass in a controller reference to the view on instantiation:
var controller = Ember.Object.create({content: {}}),
view = Ember.View.create({
controller: controller,
contentBinding: 'controller.content'
});
I'd also suggest looking into the Ember StateManager.

ASP.NET MVC 3 - pass data to a partial view in Layout

I'm working on a ASP.NET MVC 3 application, but I'm rather new to MVC in general.
I have a partial view in a my application layout view that needs to have data passed to it. this will appear on every page. Is there a way to make this happen so I don't have to load that data into the view model for every action in the entire site?
As in, if a user navigates to Mysite/admin/settings, I would like to have the partial view on the layout be able to somehow receive the data that it needs without me needing to put that code in the Settings action in the Admin controller.
On this same note, how do you pass data to the layout view of an application anyway?
In these situations I usually use a base ViewModel for my Views
public class ApplicationViewModel
{
public string UserName {get; set;}
....
}
public class SettingsViewModel : ApplicationViewModel
{
}
all your views would inherit from that ViewModel. Your layout would expect it as well
_layout.cshtml:
#model ApplicationViewModel
....
<h1>hello #Model.UserName</h1>
hopefully this answers your question
Partial only renders a view. You need to provide the model manually.
You can create an action for the view you want and render it with Html.Action( actionName ).
Make an action for example menu which will create a model that will be provided to the menu view.
Now you can call the #Html.Action("menu") from wherever, and it will be rendered autonomously. (you can ofcourse provide a controller name as well, and even custom routeData)
You might also want to set Layout = null; in the view to avoid using the master layout of the whole site.
This is how I pass a value to the partial view from my layout page:
Layout page code:
Html.RenderPartial("_SubMenuLeft", new ViewDataDictionary { {"category", "MMG"} });
and in my _SubMenuLeft.cshtml (partial view)
#if (ViewData["category"] == "MMG")
{
...
}
Hope it helps someone for future reference.

MVC3 Display templates

I've created custom Editor templates and Display templates. I've placed each of these types in a folder within my views folder. The folders were named either EditorTemplate or DisplayTemplate, depending upon which type of template was created.
So, now I can use EditorFor to use my custom editor template, or DisplayFor for my custom editor template.
I would like to create a custom template for a LabelFor, but I haven't found an example of this. Would I create a folder named Labeltemplate in my Views folder and add it here?
UPDATE
The reason I was trying to extend the LabelFor was to handle a Property that is of type KeyValuePair. I want to use the Key of this property as the Label, and the value as the Display. I asked a question here about the DisplayFor to handle the Value.
My solution ended up as>
#Html.DisplayFor(m => m.MyProperty, #Model.MyProperty.Key)
Thanks,
LabelFor doesn't use any templates. It is hardcoded in the MVC source code and it spits a <label> no matter what you do.
You will have to write a custom html helper if you want to modify this behavior.
On the other hand if you want to use templates you have to use EditorFor/DisplayFor helpers. So, since a label is for displaying purposes you could use a display template and instead of using Html.LabelFor(x => x.Foo) use Html.DisplayFor(x => x.Foo). As far as the custom template is concerned, either you decorate the Foo property with the [UIHint] attribute or pass it as second argument to the DisplayFor helper.
UPDATE:
According to your comment you are not trying to modify the markup but only the value. That's what the second argument of the LabelFor helper could be used for:
#Html.LabelFor(x => x.Foo, Model.Key)
#Html.EditorFor(x => x.Foo)
This creates a label which is associated with the Foo input (for attribute of the label properly assigned) but the text shown is that of the Key property on your view model.
There is no support for creating a template for a specific HTML Helper method (LabelFor).
You could:
Markup your model using meta descriptors to change what value gets displayed as part of the label:
[DisplayName("Custom Label")]
public string Test {get;set;}
You could create your own custom HTML Helper method for rending out a label:
How can I override the #Html.LabelFor template?
You can create a DisplayTemplate and access it via template name:
#Html.DisplayFor(x => x.Foo, "label")
And then just create a template called label.cshtml in your DisplayTemplates folder.
To simplify this call, you can write an extension method that handles this call:
public static MvcHtmlString TemplateLabelFor<TModel, TProperty>(this HtmlHelper<TModel> html, Expression<Func<TModel, TProperty>> property)
{
return html.DisplayFor(property, "label");
}

create custom controls mvc3

Just starting to get the hang of MVC3 and want to start building out some custom controls that I can just drop into a view. Specifically I want to be able to drop in some html form controls that will automatically add some javascript for validation.
something like this is what I'd want:
#Html.VTextBox("MyTextBox","",new {#vType="PhoneNumber", #vMessage="You Must Enter a Phone Number" })
when the page is rendered, I'd want it to search for any custom elements I create then drop in the appropriate javascript to validate client side. I did something very similar to this with asp.net web forms for custom controls ie
<ucc:VTextBox ID="MyTextBox" runat="server" message="You must fill this in" />
just wondering if MVC3 offers the same extensibility. Any resources or advice you can provide would be greatly appreciated.
TIA
To start off with, you'll need to look into extension methods and more specifically, how to create extension methods for the HtmlHelper class so you could write code like the example you've shown above.
For the example you've shown above, you could write code like this:
public MvcHtmlString VTextBox(string name, object value, object htmlAttributes)
{
StringBuilder html = new StringBuilder();
// Build your html however you want
// Here's a simple example that doesn't
// take into account your validation needs
html.AppendFormat("input type=\"text\" name=\"{0}\" value=\"{1}\" />", name, value);
return MvcHtmlString(html.ToString());
}
Then in your view you can use the example above like so:
#Html.VTextBox("MyTextBox","",new {#vType="PhoneNumber", #vMessage="You Must Enter a Phone Number" })
NOTE: You'll need to import the namespace the extension method is in to your view. Simplest method, put a #using ExtensionMethodNamespace at the top of your view. You can make the namespace automatically imported to all your views by fiddling with the web.config (and maybe the Global.asax).
ADDENDUM: Please note RPM1984's comment below where he advises to use TagBuilder in place of StringBuilder which is sound advice since this is the exact scenario TagBuilder was designed for. He also mentions strong typing the helper to the model which is also great advice.

Determine physical location of Razor view in MVC3

I've created my own Razor view class, thus:
public abstract class MyWebViewPage : System.Web.Mvc.WebViewPage
{
public MyWebViewPage()
{
}
}
I use this class in my cshtml file, thus:
#inherits MyWebViewPage
<html>
...
</html>
I want to determine the physical location of the cshtml file in the constructor of the class, but don't seem to be able to get a handle on anything in the base class that might tell me. Any ideas?
I'm trying to work out the Area name and folder name of the view (e.g. Areas/MyArea/Views/MyViews/MyView.cshtml). The pertinent bits being "MyArea" and "MyViews".
I'm currently porting an application to use Razor views and I used to be able to do what I needed because the class name of the view was something along the lines of:
ASP_Areas_MyArea_Views_MyViews_MyView
But with Razor it's just:
ASP_MyView
You should be able to look at the VirtualPath property. It will not be available when the constructor gets invoked, but you can override ConfigurePage and do any processing there.

Resources