ASP.Net MVC 3显示模板和编辑模板自定义位置,如何?

时间:2011-03-03 02:32:31

标签: asp.net-mvc asp.net-mvc-3 razor

我要去坚果, 我正在使用MVCContrib,使用Portable Areas创建可插拔站点,到目前为止一切运行良好,除了当我开始使用MVC模板时,发生的事情是如果我把模板放在它工作的View的相应文件夹中,实例

HostApplication/Views/Home/DisplayTemplates/FirstName.cshtml
HostApplication/Areas/PortableArea_Blog/Views/Home/DisplayTemplates/Auther.cshtml

但我真正想要的是能够创建通用模板从主机应用程序或便携式区域设置和利用它,所以为此,我创建了一个新的便携式区域,称为DisplayTemplates(利用MVCContrib能力编译视图),这里是便携式区域结构

DisplayTemplates
|-Views
  |-CommentTemplate.cshtml

现在在我的主机应用程序中我创建了一个测试模型并添加了UIHint属性

public class HostModel
    {


        [UIHint("~/Areas/DisplayTemplates/Comment.cshtml")]
        public string Name { get; set; }
    }

但它不起作用,所以我认为它与Partial Views Location有关,所以我创建了一个CustomView引擎来查找该位置的部分视图并在Global.asax中注册它,这里是一个简短的想法,所以我不会厌烦你完整的代码

public class AreaViewEngine : RazorViewEngine
    {
        public AreaViewEngine()
        {

            // {0} = View name
            // {1} = Controller name

            // View locations
            ViewLocationFormats = new[]
                                      {
                                          "~/Areas/DisplayTemplates/{0}.cshtml"

                                      };

            PartialViewLocationFormats = ViewLocationFormats;

            AreaPartialViewLocationFormats = ViewLocationFormats;
        }

        protected override IView CreatePartialView(ControllerContext controllerContext, string partialPath)
        {
            return new RazorView(controllerContext, partialPath, null, true, new[] { "cshtml" });
        }

        protected override IView CreateView(ControllerContext controllerContext, string viewPath, string masterPath)
        {
            return new RazorView(controllerContext, viewPath, masterPath, true, new[] { "cshtml" });
        }




    }
更奇怪的是,似乎那个带显式位置的UIHint显示模板,不起作用,这里是一个例子

public class HostModel
    {
        //this works
        [UIHint("FirstName")]
        //this does not work
        [UIHint("~/Views/Home/DisplayTemplates/FirstName.cshtml")]
        public string Name { get; set; }
    }

和是

FirstName.cshtml is in HostApplication/Views/Home/DisplayTemplates/FirstName.cshtml

再次为长篇文章感到抱歉,但我放弃了寻找解决方案,所以任何帮助都会完全受到赞赏。

5 个答案:

答案 0 :(得分:12)

丹尼是对的。找到模板的方式与找到部分视图的方式相同。

默认情况下,WebFormViewEngine和RazorViewEngine将在以下位置搜索模板。

对于显示模板:

  

〜/查看/ {控制器} / DisplayTemplates   〜/查看/共享/ DisplayTemplates

对于编辑器模板:

  

〜/查看/ {控制器} / EditorTemplates   〜/查看/共享/ EditorTemplates

我认为子目录的名称(即“DisplayTemplates”和“EditorTemplates”)在某处被硬编码到MVC中(我知道它是开源的,我可以找到它,但我不会去)

我认为稍微更改位置的最简单方法是覆盖ViewEngine。我的自定义ViewEngine在这一点上非常复杂,但我怀疑你可以侥幸逃脱。

假设您希望模板位于〜/ Views / Templates中。

创建一个继承自您现在使用的视图引擎的类(可能是WebFormViewEngine或RazorViewEngine)。添加一个空构造函数。它应该是这样的:

namespace MySite
{
    public class MySiteViewEngine : RazorViewEngine // <<-- or WebFormViewEngine
    {
         public MySiteViewEngine()
         {
             // We'll put some code here in a later step
         }
    }
}

现在,将以下行添加到Global.asax.cs的Application_Start方法:

ViewEngines.Engines.Clear();
ViewEngines.Engines.Add(new MySiteViewEngine());

此时,编译并运行您的应用程序。一切都应该像现在一样运行。您基本上使用的是之前使用的相同视图引擎。

但现在,我们想要在查找PartialViews时添加搜索位置。这可以通过添加到 PartialViewLocationFormats 来完成。所以,现在在自定义视图引擎的构造函数中,您希望像这样添加到基类的数组:

base.PartialViewLocationFormats = new string[] {
    "~/Views/Templates/{0}.cshtml"
}.Union(base.PartialViewLocationFormats).ToArray<string>();

关于上述内容的几点说明:

  • 上面的条目将使您的视图引擎在〜/ Views / Templates / DisplayTemplates / String.cshtml中查找String显示模板。
  • 这些视图引擎中的位置格式包括文件扩展名,所以如果你使用Razor / C#使用“cshtml”,Razor / VB使用“vbhtml”,WebForms会添加“aspx”和“ascx”。
  • 我上面的方式,我将我的位置格式添加到列表的顶部,但保留所有默认位置。您可以考虑删除它们。
  • 观看当前的格式,你会发现你也会在格式的{1}位置获得一个控制器,所以如果你想在每个控制器下面都有一个Templates目录。
  • 小心,一旦你开始使用视图引擎移动它,就会让人上瘾。你可能会发现自己在四处移动。
祝你好运。

答案 1 :(得分:8)

您可以在运行时轻松修改现有的ViewEngine,而不是创建新的ViewEngine:

private void FixMvcTemplateAreaBug(string areaName)
{
    foreach (BuildManagerViewEngine viewEngine in ViewEngines.Engines)
    {
        List<string> viewLocations = 
                     new List<string>(viewEngine.PartialViewLocationFormats);

        foreach (var extension in viewEngine.FileExtensions)
            viewLocations.Add("~/Areas/" + areaName + 
                              "/Views/Shared/{0}." + extension);

        viewEngine.PartialViewLocationFormats = viewLocations.ToArray();
    }
}

将上述内容放在适当的位置(如区域注册),你会没事的。

答案 2 :(得分:2)

我认为你没有答案,因为没有答案: - (

在过去的几天里,我一直在寻找解决方案,因为正如你所提到的那样,它有很多观点。不幸的是我无法找到任何方法来覆盖它。

我认为你被困住了:(

编辑:看过这篇文章是为了从数据库而不是磁盘中读取视图:

ASP.NET MVC load Razor view from database

我想知道DisplayTemplates是否以这种方式读取。如果是这样,您可以尝试劫持它们并从其他位置(而不是DB)读取它们吗?

答案 3 :(得分:1)

如果我遗漏了上述内容,请原谅,但有没有理由认为允许指定模板的Html.DisplayFor覆盖在这里不起作用?例如:

@Html.DisplayFor(m => m.MyItem, "~/Views/Controller/DisplayTemplates/MyItem.cshtml")

干杯,

答案 4 :(得分:1)

可能有点晚了:)但现在可以在MVC 4中使用了。通用模板必须放在~/Views/Shared/EditorTemplates

Source