65.9K
CodeProject 正在变化。 阅读更多。
Home

ASP.NET MVC 动态主题

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.36/5 (7投票s)

2009年1月26日

CPOL
viewsIcon

109142

downloadIcon

2878

在 ASP.NET MVC 中实现主题选择。

引言

我确实需要为我的应用程序启用主题,并且我找到了 Chris Pietschmann 发表的一篇关于此的文章。我认为他的方法唯一的问题是,你需要为所有主题重复每个页面。好吧,我只想为每个主题创建一个页面,并为每个主题设置母版页和 CSS 文件。

使用代码

对于这个项目,我做了一些假设

  • 每个主题的母版页名为 Site.Master
  • 母版页文件和 CSS 文件将放置在以主题名称命名的文件夹中。
  • 所有主题文件夹都将放置在 Content 文件夹中。

文件结构如下

现在,让我们编写一个继承自 WebFormViewEngine 的自定义视图引擎。这段代码只是我想实现的内容的草图。例如,我想保存用户的选择主题,以便在下次登录时,用户拥有他/她的选项设置。

public class ThemeViewEngine : WebFormViewEngine
{
    public ThemeViewEngine()
    {
        base.ViewLocationFormats = new string[] {
            "~/Views/{1}/{0}.aspx",
            "~/Views/{1}/{0}.ascx",
            "~/Views/Shared/{0}.aspx",
            "~/Views/Shared/{0}.ascx"
        };

        base.MasterLocationFormats = new string[] {
            "~/Content/{2}/Site.master"
        };

        base.PartialViewLocationFormats = new string[] {
            "~/Views/{1}/{0}.aspx",
            "~/Views/{1}/{0}.ascx",
            "~/Views/Shared/{0}.aspx",
            "~/Views/Shared/{0}.ascx"
        };
    }

    public override ViewEngineResult FindView(ControllerContext controllerContext, 
                    string viewName, string masterName)
    {
        if (controllerContext == null)
        {
            throw new ArgumentNullException("controllerContext");
        }
        if (string.IsNullOrEmpty(viewName))
        {
            throw new ArgumentException("Value is required.", "viewName");
        }

        string themeName = this.GetThemeToUse(controllerContext);

        string[] searchedViewLocations;
        string[] searchedMasterLocations;

        string controllerName = 
          controllerContext.RouteData.GetRequiredString("controller");

        string viewPath = this.GetViewPath(this.ViewLocationFormats, viewName, 
                          controllerName, out searchedViewLocations);
        string masterPath = this.GetMasterPath(this.MasterLocationFormats, viewName, 
                            controllerName, themeName, out searchedMasterLocations);

        if (!(string.IsNullOrEmpty(viewPath)) && 
           (!(masterPath == string.Empty) || string.IsNullOrEmpty(masterName)))
        {
            return new ViewEngineResult(
                (this.CreateView(controllerContext, viewPath, masterPath)), this);
        }
        return new ViewEngineResult(
          searchedViewLocations.Union<string>(searchedMasterLocations));
    }

    public override ViewEngineResult FindPartialView(ControllerContext controllerContext, 
                                                     string partialViewName)
    {
        if (controllerContext == null)
        {
            throw new ArgumentNullException("controllerContext");
        }
        if (string.IsNullOrEmpty(partialViewName))
        {
            throw new ArgumentException("Value is required.", partialViewName);
        }

        string themeName = this.GetThemeToUse(controllerContext);

        string[] searchedLocations;

        string controllerName = controllerContext.RouteData.GetRequiredString("controller");

        string partialPath = this.GetViewPath(this.PartialViewLocationFormats, 
                             partialViewName, controllerName, out searchedLocations);

        if (string.IsNullOrEmpty(partialPath))
        {
            return new ViewEngineResult(searchedLocations);
        }
        return new ViewEngineResult(this.CreatePartialView(controllerContext, 
                                    partialPath), this);
    }

    private string GetThemeToUse(ControllerContext controllerContext)
    {
        if (controllerContext.HttpContext.Request.QueryString.AllKeys.Contains("theme"))
        {
            string themeName = controllerContext.HttpContext.Request.QueryString["theme"];
            controllerContext.HttpContext.Session.Add("Theme", themeName);
        }
        else if (controllerContext.HttpContext.Session["Theme"] == null)
        {
            controllerContext.HttpContext.Session.Add("Theme", "Default");
        }
        return controllerContext.HttpContext.Session["Theme"].ToString();
    }

    private string GetViewPath(string[] locations, string viewName, 
                   string controllerName, out string[] searchedLocations)
    {
        string path = null;

        searchedLocations = new string[locations.Length];

        for (int i = 0; i < locations.Length; i++)
        {
            path = string.Format(CultureInfo.InvariantCulture, locations[i], 
                                 new object[] { viewName, controllerName });
            if (this.VirtualPathProvider.FileExists(path))
            {
                searchedLocations = new string[0];
                return path;
            }
            searchedLocations[i] = path;
        }
        return null;
    }

    private string GetMasterPath(string[] locations, string viewName, 
                   string controllerName, string themeName, out string[] searchedLocations)
    {
        string path = null;

        searchedLocations = new string[locations.Length];

        for (int i = 0; i < locations.Length; i++)
        {
            path = string.Format(CultureInfo.InvariantCulture, locations[i], 
                                 new object[] { viewName, controllerName, themeName });
            if (this.VirtualPathProvider.FileExists(path))
            {
                searchedLocations = new string[0];
                return path;
            }
            searchedLocations[i] = path;
        }
        return null;
    }
}

为了完成这个示例,只需更改 global.asax,删除视图引擎中的所有引擎并添加自定义引擎

protected void Application_Start()
{
    RegisterRoutes(RouteTable.Routes);

    ViewEngines.Engines.Clear();
    ViewEngines.Engines.Add(new ThemeViewEngine());
}

希望这有帮助。

© . All rights reserved.