首页 新闻 会员 周边

关于MVC3实现多视图模版的问题(ViewEngine相关,高手请进)

0
悬赏园豆:100 [已解决问题] 解决于 2012-09-10 11:49

需求:网站为两个角色的客户提供独立站点服务,每个角色的站点风格布局都不一样,但内容一样。要求用户访问不同的角色对应的站点时,加载相应的view视图模版。

疑问:使用ViewEngine的话,好像是在global中就直接注册死了,而我更希望在我的controller中去控制,实现不同角色返回不同的view,那么如何实现?

期待高手解答!

笑看山河的主页 笑看山河 | 初学一级 | 园豆:72
提问于:2012-09-04 18:19
< >
分享
最佳答案
1
View Code
 1 public class CustomRazorViewEngine : RazorViewEngine
 2     {
14         public override ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache)
15         {
16             if (controllerContext.RouteData.Values["id"].ToString() == "1")
17             {
18                 this.ViewLocationFormats = new string[] { "~/Views/{1}/{0}.cshtml", "~/Views/{0}.cshtml" };
19             }
20             else
21             {
22                 this.ViewLocationFormats = new string[] { "~/Views/Common/{1}/{0}.cshtml", "~/Views/Common/{0}.cshtml" };
23             }
24             return base.FindView(controllerContext, viewName, masterName, useCache);
25         }
26     }

1. 继承默认的RazorViewEngine

2. 重写FindView方法

3. 关键地方是根据不同的参数,设置查找View的不同路径-> ViewLocationFormats

4. 注意在Global.asax中,注册CustomRazorViewEngine

  ViewEngines.Engines.Insert(0, new CustomRazorViewEngine());

  将自定义的ViewEngine通过Insert放在最前面,自定义的Engine会最先执行

收获园豆:80
mooboo | 菜鸟二级 |园豆:282 | 2012-09-06 17:41

ok,好方法哈,试试,多谢啦!

笑看山河 | 园豆:72 (初学一级) | 2012-09-10 09:15

问题解决,谢谢,结贴!

笑看山河 | 园豆:72 (初学一级) | 2012-09-10 11:47

@笑看山河: 我把CustomRazorViewEngine 写在Global.asax文件里面的,执行controllerContext.RouteData.Values["id"]的时候会报错误,错误信息:未将对象引用设置到对象的实例。请问怎么样弄啊

Haydy | 园豆:177 (初学一级) | 2013-03-14 14:09

这样是根据条件来选择不同的view,View都是写死成固定的.cshtml文件的,我现在的需求是.cshtml文件的内容在数据库,如何动态的替换呢。我的view里只有一个div,根据不同的条件我会加载不同的内容到div里。然后再让razor去解析

寒_飞 | 园豆:204 (菜鸟二级) | 2013-12-11 10:07
其他回答(4)
0
View Code
Global.asax:

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


public class FormBuilderViewEngine : RazorViewEngine
    {
        public FormBuilderViewEngine()
        {
            ViewLocationFormats = new[] {
                "~/Views/FormBuilder/{1}/{0}.cshtml"
            };
            MasterLocationFormats = new[] {
                "~/Views/Shared/{0}.cshtml"
            };
            PartialViewLocationFormats = new[] {
                "~/Views/Shared/{0}.cshtml",
            };

            FileExtensions = new[] {
                "cshtml"
            };
        }

        protected override IView CreatePartialView(ControllerContext controllerContext, string partialPath)
        {
            return new RazorView(controllerContext, partialPath,
                                 layoutPath: null, runViewStartPages: false, viewStartFileExtensions: FileExtensions, viewPageActivator: ViewPageActivator);
        }

        protected override IView CreateView(ControllerContext controllerContext, string viewPath, string masterPath)
        {
            string formId = (controllerContext.RouteData.Values["id"] ?? "").ToString();
            if (!string.IsNullOrEmpty(formId) && 
                controllerContext.RouteData.Values["controller"].ToString()=="Home" &&
                controllerContext.RouteData.Values["action"].ToString() == "Index"
                )
            {
                string[] names = formId.Split('_');
                string functionName = "Home";
                string pageName = "Index";

                pageName = names[0];
                if (names.Length > 1)
                {
                    functionName = names[0];
                    pageName = names[1];
                }

                viewPath = string.Format(ViewLocationFormats[0], pageName, functionName);
            }
            masterPath = string.Format(MasterLocationFormats[0], "_Layout");
            var view = new RazorView(controllerContext, viewPath,
                                     layoutPath: masterPath, runViewStartPages: false, viewStartFileExtensions: FileExtensions, viewPageActivator: ViewPageActivator);
            return view;
        }
    }


//上面我是根据id来使用不同的视图,你也可以根据条件使用不同的masterPath 
收获园豆:10
向往-SONG | 园豆:4853 (老鸟四级) | 2012-09-04 18:29

3KO,感谢支持哈,测试下先!

支持(0) 反对(0) 笑看山河 | 园豆:72 (初学一级) | 2012-09-05 09:24

按照你的方案处理了,但死活不行。也跟踪不到。代码如下,程序执行时设置断点根本进不到这个地方,帮看下,谢谢

 protected override IView CreateView(ControllerContext controllerContext, string viewPath, string masterPath)
        {
            string controller = controllerContext.RouteData.Values["controller"].ToString();
            if (controller.ToLower() == "site")
            {
                int id = (int)controllerContext.RouteData.Values["id"];
                if (id == 1)
                {
                    viewPath = "~/Views/StarBuilder/{1}/{0}.cshtml";
                }
                else
                {
                    viewPath = "~/Views/StarTeam/{1}/{0}.cshtml";
                }
            }
            var view = new RazorView(controllerContext, viewPath, layoutPath: masterPath, runViewStartPages: true, viewStartFileExtensions: FileExtensions, viewPageActivator: ViewPageActivator);
            return view;
        }
支持(0) 反对(0) 笑看山河 | 园豆:72 (初学一级) | 2012-09-05 15:50

@笑看山河: 

有写ViewEngines.Engines.Clear()吗?没写会进默认的ViewEngine。
路由也要正确,先不加Clear(),能正确进到对应路由的action后再加上。
比如路由是:

"{controller }/{action}/{id}",
new { controller = "Home", action = "Index",id = UrlParameter.Optional}

那你也必须要有Views/StarBuilder/Home/Index.cshtml这个文件

支持(0) 反对(0) 向往-SONG | 园豆:4853 (老鸟四级) | 2012-09-05 16:31

@向往-SONG: 这些都有的,现在发现就是第一次能跟踪进来,只有就不行了,好像缓存了。另外,我的代码不知道写的是否正确,现在总提示找不到页面。

未找到视图“index”或其母版视图,或没有视图引擎支持搜索的位置。搜索了以下位置: ~/Views/Site/index.aspx

支持(0) 反对(0) 笑看山河 | 园豆:72 (初学一级) | 2012-09-06 11:57

@笑看山河: 

加一个/Views/Site/index.aspx,未改变viewPath前,它会去找这个视图。

支持(0) 反对(0) 向往-SONG | 园豆:4853 (老鸟四级) | 2012-09-06 12:36

@笑看山河: 我把CustomRazorViewEngine 写在Global.asax文件里面的,执行controllerContext.RouteData.Values["id"]的时候会报错误,错误信息:未将对象引用设置到对象的实例。请问怎么样弄啊

支持(0) 反对(0) Haydy | 园豆:177 (初学一级) | 2013-03-14 14:10
0

两种方法。如果只是风格样式不一样的话。分主题包就行了,路径不一样。

比如:  Content/themes/style1  , Content/themes/style1 

然后引用的时候不同的地方 就弄个变量。比如 (ViewBag.Theme) 。然后怎么做相信你也懂得。

建议最好弄个基类Controller。

如果连布局也不一样的话。 那就得分不同母版页咯。

用到这个重载方法 ViewResult View(string viewName, string masterName);

收获园豆:10
心灵工程师 | 园豆:198 (初学一级) | 2012-09-04 21:40
0

请问在Controller如何加载并return 指定的View?

Elaine_Li | 园豆:161 (初学一级) | 2012-10-31 11:45

方法一:return view("~/view/xxx/xxx.cshtml")

方法二:如果你需要规则化的指定,那么你可以参考“最佳答案”中的方法,我的就是用这种方式实现自定义模版的!

支持(0) 反对(0) 笑看山河 | 园豆:72 (初学一级) | 2012-10-31 11:50

@笑看山河: 第一种是可以的,但第二种我试了下,但有问题?有单独实例的源码吗?

支持(0) 反对(0) Elaine_Li | 园豆:161 (初学一级) | 2012-10-31 13:14
-2

能指点一下吗?我的qq498669416,谢谢了

Haydy | 园豆:177 (初学一级) | 2013-03-14 14:10
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册