I wrote a site a while back where I had different tabs that went to different places for different users. I'll walk you through my solution hopefully I understood the question correctly and some of this helps.
As far as getting data to and from the View, I do use the ViewDataDictionary. To the best of my knowledge, that's what it's for when your model doesn't consist of a single simple object. In order to get around the "magic strings" of view keys, I create a bunch of extension methods on the ViewDataDictionary. This has the drawback that you end up with a slew of extra methods, but at least all of your string keys are isolated in a single location. You could even go the extra step of create constants in the class, but it seems redundant when only this class uses them. Extension properties would be better but...
/// <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;
}
You'll notice that I have an explicit view object, TabItemDisplay, that I pass into the dictionary. This contains all of the values necessary to pass to 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; }
}
Since this view is not the main content of the page, I prefer to put the logic of creating the tab items, including destination parameters, into an ActionFilter. This allows me to reuse the tab creation logic across different actions and controllers. Any View that contains the tab partial control gets the CreatTabAttribute slapped across the corresponding Action or Controller and it's good to go.
This may be more than you needed, but I hope some of it helps.
EDIT: Just realized I didn't include what this looks like in the partial view. I actually have an HtmlHelper extension that renders a more intricate tab, but you get the idea.
<%@ 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>
EDIT: Adding a short example of the ActionFilter I use.
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);
}
}
This is only a basic example of pulling tabs from a repository (instantiated using StructureMap), and a simple check to see if the user is authenticated. But you can do other things such as pull the requested user id for the user being displayed from routeValues.