开发者

Is is possible to specify searchable location formats for an MVC Razor Layout?

In Razor, when loading a partial view, it is possible to just specify the partial view name, and the Razor view engine will search the RazorViewEngine.PartialViewLocationFormats开发者_如何转开发:

@Html.RenderPartial("_PartialView", Model);

will actually search the locations specified in PartialViewLocationFormats in the view engine, such as for example

~/Views/Home/_PartialView.cshtml
~/Views/Shared/_PartialView.cshtml

However, when specifying the Layout, I seem to be forced to specify a specific path to the layout:

@Layout = "~/Views/Shared/MyLayout.cshtml";

What I would like to do would be to specify the layout just by name, and have the the actual layout be found by searching a list of common locations:

@Layout = "MyLayout";

...but I can't find any facilities to do so. Since I could not find any documentation regarding this, I tried playing with setting RazorViewEngine.MasterLocationFormats, but this property is not used when locating layouts.

Does anybody know how to do this?


Recently I was struggling on a similar issue where, in a themed application that uses a custom ViewEngine to search theme's location first for views, I was trying to override some master files. One way to force the location of the layout to go through the ViewEngine's FindView is to specify the name of the master view in a controller action when returning:

return View("myView", "myViewMaster");

However, if "myViewMaster" also has a layout (nested layouts), this method doesn't work for the nested layout. My best solution so far is to call the view engine directly in the view:

@{
    Layout = (ViewEngines.Engines.FindView(this.ViewContext.Controller.ControllerContext, "myViewMaster", "").View as RazorView).ViewPath;
}

This works but could certainly be encapsulated in a extension method to avoid repetition and abstract the code.

Hope it helps!


I tried a couple of different things and couldn't find a way to do what you wanted. However, you could just leave the Layout blank and use the _ViewStart.cshtml file to assign the layout for each page using a ViewBag property is something.

So if you had an enum (for instance) and you set the dynamic viewbag property of CustomLayout to a value of that enum, you could use the _ViewStart file to do something like this.

@{  
    MvcApplication12.Controllers.CustomLayouts customLayout = this.ViewContext.Controller.ViewBag.CustomLayout;

    switch (customLayout)
    {
        case MvcApplication12.Controllers.CustomLayouts.Blue: Layout = "~/Views/Shared/Blue.cshtml"; break;
        case MvcApplication12.Controllers.CustomLayouts.Green: Layout = "~/Views/Shared/Green.cshtml"; break;
        case MvcApplication12.Controllers.CustomLayouts.Default:
        default: Layout = "~/Views/Shared/Default.cshtml"; break;
    }   
}

Not sure if this helps or not.


I took the accepted answer from @sowee15 and added an extension method to help wrap it up a bit:

using System;
using System.Web.Mvc;

namespace MyApp.Classes
{
    public static class ViewEngineCollectionExtensions
    {
        public static string FindViewPath(this ViewEngineCollection viewEngines, ControllerContext controllerContext, string viewName, string masterName = null)
        {
            var viewResult = ViewEngines.Engines.FindView(controllerContext, viewName, masterName ?? string.Empty);
            if(viewResult == null)
                throw new Exception(string.Format("The specified view {0} could not be found.", viewName));

            var view = viewResult.View as RazorView;
            if(viewResult == null)
                throw new Exception(string.Format("The specified view {0} must be a Razor view.", viewName));

            return view.ViewPath;
        }
    }
}

Then you can call extension from your view or viewstart.cshtml like so:

@{
    Layout = ViewEngines.Engines.FindViewPath(ViewContext.Controller.ControllerContext, "_PopupLayout");
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜