我正在尝试找出在ASP.NET MVC中创建导航菜单的最佳方法,该导航菜单可以根据构建它的控制器操作进行更改(它也会根据用户权限等而有所不同)。导航菜单显示在母版页中,并且我们所有的视图都是强类型的。
我想在一个基本控制器中使用OnActionExecuting来填充标准菜单,然后在每个控制器操作中相应地修改它。但是,这似乎不是一个选项,因为视图模型在调用我的操作之前是不可用的。
我能想到的另一件事就是在基本的ViewModel构造函数中预先填充menu对象。然后我可以在我的控制器操作中根据需要添加/删除。不过,这似乎并不完全合适,因为我需要在ViewModel构造函数中实例化回控制器操作的链接(因为每个菜单项都可以有一个控制器/操作/id)。
有什么建议是最好的方法吗?特别是对于基于上下文而显著改变的导航菜单(或可能的树视图)。
发布于 2009-11-04 06:53:50
我使用MasterModel来处理这类事情。
在我看来,.aspx和它的.master是可分离的(例如,你可以在渲染aspx的时候换掉母版;而且aspx不是从母版继承的,它只使用母版),因此视图模型也应该是分开的。(即PageModel不应从MasterModel继承。)
aspx可能只关心接收,比方说,一个IEnumerable,为什么它的视图模型要继承一些公共类?
因此,不是:
public class MasterModel
{
public string Title { get; set; }
public MenuModel Menu { get; set; }
}
public class PageViewModel
: MasterModel
{
public IEnumerable<Foo> TheOnlyThingInTheWorldMyPageReallyCaresAbout { get; set; }
}
public ActionResult TheAction()
{
var items = GetItems();
var model = new PageViewModel {
TheOnlyThingInTheWorldMyPageReallyCaresAbout = items
};
return view("Viewname", model);
}我使用:
public class BaseController
: Controller
{
protected MasterModel MasterModel
{
get { return ViewData["MasterModel"] as MasterModel; }
set { ViewData["MasterModel"] = value; }
}
}
public class MasterModel
{
public MasterModel()
{
// Sensible defaults
}
public string Title { get; set; }
public MenuModel Menu { get; set; }
}
public ActionResult TheAction()
{
var items = GetItems();
// Prepare the MasterModel as part of the controller's "select and prepare the view" responsibility.
// Common cases can be factored into ActionFilter attributes or to a base Controller class.
MasterModel = new MasterModel();
return view("Viewname", items);
}然后,您可以将此代码添加到母版页中:
<%@ Master Language="C#" Inherits="System.Web.Mvc.ViewMasterPage" %>
<script runat="server">
public MasterModel Model { get { return ViewData["MasterModel"] as MasterModel; } }
</script>现在,您不必对页面视图模型执行任何特殊操作。他们可以只关心他们应该关心的事情。
为什么所有这些转弯抹角的东西都很有趣?
我想在一个基本控制器中使用OnActionExecuting来填充标准菜单,然后在每个控制器操作中相应地修改它。但是,这似乎不是一个选项,因为视图模型在调用我的操作之前是不可用的。
我能想到的另一件事就是在基本的ViewModel构造函数中预先填充menu对象。然后我可以在我的控制器操作中根据需要添加/删除。不过,这似乎并不完全合适,因为我需要在ViewModel构造函数中实例化回控制器操作的链接(因为每个菜单项都可以有一个控制器/操作/id)。
现在很容易做到这些,独立于你的页面视图模型:
MasterModel = this.DefaultMasterModel();
// -- or --
MasterModel = this.DefaultMasterModel();
this.AlterMenu(MasterModel.Menu);
// -- or --
MasterModel = new MasterModel();
MasterModel.Menu = this.SpecialReplacementMenu();
// -- or --
MasterModel = new NestedMasterModel();
// -- or --
public class FlyingPigAttribute : ActionFilterAttribute
{
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
var viewResult = filterContext.Result as ViewResult;
if (viewResult!=null)
{
var masterModel = viewResult.ViewData["MasterModel"] as MasterModel;
MakePigsFly(masterModel);
}
}
} 虽然没有给出一个具体的解决方案,但这是否为您提供了如何重构代码以使其看起来更好的选择?
发布于 2009-07-26 08:19:16
MvcContrib中的SubControllers似乎是您问题的合适解决方案。
https://stackoverflow.com/questions/1183640
复制相似问题