Jack
Jack

Reputation: 4904

MVC3 View Inheritance not possible?

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?)

Upvotes: 11

Views: 10721

Answers (4)

Jack
Jack

Reputation: 4904

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

Upvotes: 1

AdamCrawford
AdamCrawford

Reputation: 5108

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

Upvotes: 7

Russ Cam
Russ Cam

Reputation: 125488

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.

Upvotes: 7

Darin Dimitrov
Darin Dimitrov

Reputation: 1038830

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.

Upvotes: 1

Related Questions