ASP.NET MVC导航路由,根据查看的数据进行更改

时间:2010-10-11 21:01:58

标签: c# asp.net-mvc asp.net-mvc-2

我正在创建标签式导航,其中路线位置可能会有所不同。用于呈现选项卡的参数应基于当前查看的数据(当它是用户时,可能不是登录用户)。

在示例图像中,这是一个用户。因此,如果我正在看安德鲁斯蒂尔,那么链接应该与安德鲁斯蒂尔(安德鲁的总结,计算机,帐户等)有关。当我看布鲁斯汉密尔顿时,链接应该与布鲁斯汉密尔顿有关(布鲁斯的总结,计算机,帐户等)。

Example of Tabbed Navigation

我已经通过在每个ViewModel中粘贴必要的参数值然后将值传递给部分来呈现链接来解决这个问题。这感觉很糟糕。我宁愿不将链接参数数据推送到每个ViewModel中。将Html.ActionHtml.RenderAction与ViewData Dictionary值结合使用似乎是合理的,但我倾向于避免在可能的情况下使用“魔术字符串”。

有没有更好的方法将参数值输入到我缺少的视图中?

4 个答案:

答案 0 :(得分:1)

您可以为此创建一个显示选项卡首选项的视图模型。如果每个选项卡完全不同,您可以使用一个viewmodel基类来公开选项卡首选项,每个选项卡都可以有自己的视图模型。

答案 1 :(得分:1)

我曾经写过一个网站,我有不同的标签,为不同的用户转到不同的地方。我会引导你完成我的解决方案,希望我能正确理解这个问题,其中一些有帮助。

至于从View获取数据,我使用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中。这允许我在不同的动作和控制器之间重用标签创建逻辑。包含选项卡部分控件的任何视图都会在相应的操作或控制器上获取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。

答案 2 :(得分:1)

就个人而言,我会根据性能要求和品味使用MVC期货的RenderAction或渲染部分调用。

RenderAction的优点是您不需要将所有必需的渲染数据传递给委托控制器操作,因为它可以自己进行查找。部分视图需要您的主页面有足够的视图数据来呈现选项卡。无论哪种方式,它只有两个for循环(一个用于选项卡列表,一个用于选项卡渲染)和模型中的一些额外数据。

答案 3 :(得分:-1)

一种解决方案是创建基本控制器并让所有ur控制器继承它。在基本控制器中你可以在viewmodel中添加必要的值

public applicationController:Controller
{
   ViewData["linkvals"] = someValues;
}

public HomeContorller:ApplicationController{}

第二个解决方案是创建一个基本视图模型,让所有你的视图模型继承它。在基本视图模型的构造函数中,您可以创建链接值并将它们分配给ur属性

public baseViewModel
{
   public LinkVal{get;set;}
   public baseViewModel()
   {
      //calculate link vals
   }
}

public ViewModelA:baseViewModel{}