MVC3 View Inheritance not possible?
Solution 1
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://www.asp.net/mvc/tutorials/creating-custom-html-helpers-cs
Solution 2
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.
Solution 3
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
Solution 4
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.
Related videos on Youtube
Jack
Updated on June 04, 2022Comments
-
Jack about 2 years
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?)
-
Jack almost 13 yearsI can't see anyway to override a @helper ?
-
Jack almost 13 yearsthanks for the idea - but using @section is too chaotic for serious web apps
-
Jack almost 13 yearswhy doesn't @helper work in the same way? who thinks up this rubbish?
-
marcind almost 13 years@Jack I am one of those people who think this up. We designed Razor views to be biult up using composition, not inheritance.
-
Darin Dimitrov almost 13 years@marcind, thank you very much for this decision. Razor is a really wonderful view engine.
-
Jack almost 13 yearsin 2 hours I wrote a custom tool that converts cshtml-like syntax into cs files (either ashx, App_Code, or in a DLL) This basic approach can do everything MVC3 and Razor can do by just using the existing csharp language features. If you hadn't realised OOP was designed to solve these very problems! You don't need "sections" and "layouts" when you have classes and methods! I hoped you guys had learnt from the ASPX webform fiasco, but clearly not. Ivory tower bs.
-
Darin Dimitrov almost 13 years@Jack, that's really good for you. I hope your issues are solved now and you enjoy a nice drink. At least that's what I did for the past 2 hours :-)
-
AdamCrawford almost 13 yearsThe point was really that there isn't a need for inheritance for Views in the MVC model if you have the ability to define methods that are available to all your views anyway. Add the App_Code folder, put a .cshtml file in it that contains your helpers and call those to give you your shared helper functions. You could mentally model this as single layer inheritance if it makes you feel more comfortable. Really, anything complex that isn't rendering - the sort of stuff that would actually require a complex inheritance model, should be done in the model (which can have inheritance).
-
Jack almost 13 yearsI will be drinking beer when you are paying the "stupid tax" dealing with out-of-band updates, missing features appearing in the extension gallery, problems with next version of VS, etc. whilst my system carries on working just fine - to be honest I wrote it 6 years ago - when I first saw ASPX - just laughing at how "new" approach from ms is still almost as bad as that kludge. Pro devs do not use this stuff.