ASP.NET MVC 动态主题






4.36/5 (7投票s)
在 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());
}
希望这有帮助。