在 MVC _Layout.cshtml 页面中设置背景
Setting the background in an MVC _Layout.cshtml page
在 ASP.Net WebForms 中设置每个页面的背景相当简单,您可以在 MasterPage 的代码隐藏中访问 Page_Load 事件,但是如何在 MVC 中最好地完成这项工作?在花了几个小时研究各种替代方案后,我选择通过 "base" 控制器将值分配给 ViewBag,从该基础派生后续控制器,然后在 _Layout.cshtml.
中访问该值
这是基本控制器,我在其中分配了一个指向特定图像的 url:
public class BaseController : Controller
{
public BaseController()
{
ViewBag.url = BingImageLoader.getBingImageUrl();
}
}
下一步是派生后续控制器,在本例中是来自该基础的 HomeController class:
public class HomeController : BaseController
{
public ActionResult Index()
{
return View();
}
.
.
最后,使用 _Layout.cshtml 的 head 元素中的 ViewBag 设置背景图像样式 属性。
.
.
<style type="text/css">
body {
background-image: url(@ViewBag.url);
background-repeat: no-repeat;
background-size: cover;
}
</style>
</head>
这确实完成了我打算做的事情;然而,在此过程中,有许多替代方案被指出,包括使用 ActionFilters。老实说,创建 CustomActionFilter 并使用 ActionFilterAttributes 并重写 OnActionExecuting 似乎有点矫枉过正,但有时最简单的方法并不总是最好的。
最终,问题归结为 "Is there a better way?" 引入中介是否有副作用?如果我在各个控制器方法中覆盖我的 ViewBag.url,图像会相应改变。所以我还没有发现任何问题,但这种方法可能会导致其他问题。
那么,"Is there a better way"?
我可以看到这种方法的一个可能问题是,如果开发人员忘记从 BaseController
.
继承 hist 控制器
使用 global action filter
将确保这种情况永远不会发生并且 属性 将始终可用:
public class BackgroundImageFilterAttribute : ActionFilterAttribute
{
public override void OnActionExecuted(ActionExecutedContext context)
{
context.Controller.ViewBag.url = BingImageLoader.getBingImageUrl();
}
}
它只会在您的 Application_Start
:
中注册一次
protected void Application_Start()
{
...
// Register global filter
GlobalFilters.Filters.Add(new BackgroundImageFilterAttribute());
}
如果您发现这种过滤器方法作为替代方法很麻烦,我建议您编写一个自定义 Html 帮助程序,可以在您的 _Layout.cshtml
:
中使用
<style type="text/css">
body {
background-image: url(@Html.GetBackgroundImageUrl());
background-repeat: no-repeat;
background-size: cover;
}
</style>
这可能被定义为一个简单的扩展方法:
public static class HtmlExtensions
{
public static IHtmlString GetBackgroundImageUrl(this HtmlHelper html)
{
string url = BingImageLoader.getBingImageUrl();
return new HtmlString(url);
}
}
在 ASP.Net WebForms 中设置每个页面的背景相当简单,您可以在 MasterPage 的代码隐藏中访问 Page_Load 事件,但是如何在 MVC 中最好地完成这项工作?在花了几个小时研究各种替代方案后,我选择通过 "base" 控制器将值分配给 ViewBag,从该基础派生后续控制器,然后在 _Layout.cshtml.
中访问该值这是基本控制器,我在其中分配了一个指向特定图像的 url:
public class BaseController : Controller
{
public BaseController()
{
ViewBag.url = BingImageLoader.getBingImageUrl();
}
}
下一步是派生后续控制器,在本例中是来自该基础的 HomeController class:
public class HomeController : BaseController
{
public ActionResult Index()
{
return View();
}
.
.
最后,使用 _Layout.cshtml 的 head 元素中的 ViewBag 设置背景图像样式 属性。
.
.
<style type="text/css">
body {
background-image: url(@ViewBag.url);
background-repeat: no-repeat;
background-size: cover;
}
</style>
</head>
这确实完成了我打算做的事情;然而,在此过程中,有许多替代方案被指出,包括使用 ActionFilters。老实说,创建 CustomActionFilter 并使用 ActionFilterAttributes 并重写 OnActionExecuting 似乎有点矫枉过正,但有时最简单的方法并不总是最好的。
最终,问题归结为 "Is there a better way?" 引入中介是否有副作用?如果我在各个控制器方法中覆盖我的 ViewBag.url,图像会相应改变。所以我还没有发现任何问题,但这种方法可能会导致其他问题。
那么,"Is there a better way"?
我可以看到这种方法的一个可能问题是,如果开发人员忘记从 BaseController
.
使用 global action filter
将确保这种情况永远不会发生并且 属性 将始终可用:
public class BackgroundImageFilterAttribute : ActionFilterAttribute
{
public override void OnActionExecuted(ActionExecutedContext context)
{
context.Controller.ViewBag.url = BingImageLoader.getBingImageUrl();
}
}
它只会在您的 Application_Start
:
protected void Application_Start()
{
...
// Register global filter
GlobalFilters.Filters.Add(new BackgroundImageFilterAttribute());
}
如果您发现这种过滤器方法作为替代方法很麻烦,我建议您编写一个自定义 Html 帮助程序,可以在您的 _Layout.cshtml
:
<style type="text/css">
body {
background-image: url(@Html.GetBackgroundImageUrl());
background-repeat: no-repeat;
background-size: cover;
}
</style>
这可能被定义为一个简单的扩展方法:
public static class HtmlExtensions
{
public static IHtmlString GetBackgroundImageUrl(this HtmlHelper html)
{
string url = BingImageLoader.getBingImageUrl();
return new HtmlString(url);
}
}