不久前,我写了一个网站,其中有不同的标签,可以为不同的用户转到不同的地方。我将引导您完成我的解决方案,希望我正确理解了这个问题并且其中的一些帮助。
就在视图中获取数据和从视图中获取数据而言,我确实使用了 ViewDataDictionary。据我所知,这就是您的模型不包含单个简单对象时的用途。为了绕过视图键的“魔术字符串”,我在 ViewDataDictionary 上创建了一堆扩展方法。这样做的缺点是您最终会使用大量额外的方法,但至少您的所有字符串键都被隔离在一个位置。您甚至可以在类中创建常量的额外步骤,但是当只有这个类使用它们时,这似乎是多余的。扩展属性会更好,但是...
/// <summary>
/// Gets the list of tabs to show.
/// </summary>
/// <param name="dictionary"></param>
/// <returns></returns>
public static IList<TabItemDisplay> TabListGet(this ViewDataDictionary dictionary)
{
IList<TabItemDisplay> result;
if (dictionary.ContainsKey("TabList"))
result = dictionary["TabList"] as IList<TabItemDisplay>;
else
result = null;
return result;
}
/// <summary>
/// Sets the list of tabs to show.
/// </summary>
/// <param name="dictionary"></param>
/// <param name="tabList"></param>
/// <returns></returns>
public static IList<TabItemDisplay> TabListSet(this ViewDataDictionary dictionary, IList<TabItemDisplay> tabList)
{
dictionary["TabList"] = tabList;
return tabList;
}
您会注意到我有一个明确的视图对象 TabItemDisplay,我将它传递到字典中。这包含传递给 Html.ActionLink 所需的所有值。
public class TabItemDisplay
{
public string Name { get; set; }
public string Action { get; set; }
public string Controller { get; set; }
public object RouteValues { get; set; }
}
由于这个视图不是页面的主要内容,所以我更喜欢把创建标签项的逻辑,包括目标参数,放到一个ActionFilter中。这使我可以跨不同的操作和控制器重用选项卡创建逻辑。任何包含选项卡部分控件的 View 都会在相应的 Action 或 Controller 上获得 CreatTabAttribute,这很好。
这可能超出了您的需要,但我希望它对您有所帮助。
编辑:刚刚意识到我没有在局部视图中包含它的样子。我实际上有一个 HtmlHelper 扩展,它可以呈现一个更复杂的选项卡,但你明白了。
<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %>
<div id="tabs">
<%
if (null != ViewData.TabListGet()) {
foreach(var item in ViewData.TabListGet()) {
%>
<%= Html.ActionLink(item.Name, item.Action, item.Controller, item.RouteValues, null)%>
<%
}
}
%>
</div>
编辑:添加我使用的 ActionFilter 的简短示例。
public class CreateContentTabsAttribute : ActionFilterAttribute
{
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
var result = filterContext.Result as ViewResultBase;
if (null == result) return;
var routeValues = filterContext.RouteData.Values;
var repository = ObjectFactory.GetInstance<ITabRepository>();
var context = filterContext.HttpContext;
var userName = context.User.Identity.Name; // Or get id from Membership.
var tabs = repository.ReadByUserId(userName);
TabItemDisplay defaultTab = null;
var tabItems = new List<TabItemDisplay>();
foreach (var tab in tabs)
{
var tabItem = new TabItemDisplay
{
Name = tab.Name,
Action = "View",
Controller = "Tab",
RouteValues = new { key = tab.Key }
};
tabItems.Add(tabItem);
}
if (context.Request.IsAuthenticated)
{
tabItems.Add(new TabItemDisplay
{
Name = "Account",
Action = "ChangePassword",
Controller = "Account",
RouteValues = new { siteKey = site.Key }
});
}
result.ViewData.TabListSet(tabItems);
}
}
这只是从存储库中提取选项卡的一个基本示例(使用 StructureMap 实例化),以及一个简单的检查以查看用户是否已通过身份验证。但是您可以做其他事情,例如从 routeValues 中为正在显示的用户提取请求的用户 ID。