hengj
hengj

Reputation: 97

How to define name of an MVC action and call it

I have a Helper class that sets the current controller as the active navbar item. It also accounts for dropdown navigation.

public static MvcHtmlString MenuItem(
this HtmlHelper htmlHelper,
string text,
string action,
string controller,
Dictionary<string, string> dropdown
)
{
    var li = new TagBuilder("li");
    var dropdownList = new TagBuilder("ul");
    var routeData = htmlHelper.ViewContext.RouteData;
    var currentAction = routeData.GetRequiredString("action");
    var currentController = routeData.GetRequiredString("controller");
    if (string.Equals(currentAction, action, StringComparison.OrdinalIgnoreCase) &&
        string.Equals(currentController, controller, StringComparison.OrdinalIgnoreCase))
    {
        li.AddCssClass("active");
    }
    li.AddCssClass("menuitem");

    if(dropdown != null)
    {
        li.AddCssClass("dropdown");
        foreach (var item in dropdown)
        {
            var dropdownli = new TagBuilder("li");
            dropdownli.InnerHtml = htmlHelper.ActionLink(item.Key, item.Key, item.Value, null, null).ToHtmlString();
            dropdownList.InnerHtml += dropdownli;
        }
        dropdownList.AddCssClass("dropdown-menu");
        li.InnerHtml = htmlHelper.ActionLink(text, action, controller, null, new { @class="dropdown-toggle", data_toggle="dropdown"}).ToHtmlString() + dropdownList.ToString();
    }
    else
    {
        li.InnerHtml = htmlHelper.ActionLink(text, action, controller).ToHtmlString();
    }

    return MvcHtmlString.Create(li.ToString());
}

The Helper class is called in the _Layout.cshtml like this:

@Html.MenuItem("Home", "Index", "Home", null)
@Html.MenuItem("News", "Index", "News", null)
@Html.MenuItem("Media", "Index", "Media",
         new Dictionary<string, string>() {{ "Photos", "Media" }, 
                                           { "Videos", "Media" }})
@Html.MenuItem("Events", "Index", "Events", 
    new Dictionary<string, string>() {{ "FirstEvent", "Events" }, 
                                      { "SecondEvent", "Events" }})
@Html.MenuItem("Donate", "Index", "Donate", 
    new Dictionary<string, string>() {{ "Sponsor", "Donate" }})

The problem is that for each navbar item, the name of each link is the name of the action, meaning that if the action is "FirstEvent", it would be displayed as "FirstEvent" instead of "First Event".

Is there anyway that I could do something like [ActionName("First Event")] to set the name and then call it in the Helper class?

[ActionName("Culture Show")]
    public ActionResult CultureShow()
    {
        return View();
    }

Upvotes: 0

Views: 233

Answers (1)

danludwig
danludwig

Reputation: 47375

You could use reflection to scan the ActionName attribute off of the action method, but it seems an easier solution would be to use a model instead of a dictionary.

public class HyperlinkDataModel
{
    public string LinkText { get; set; }
    public string ActionName { get; set; }
    public string ControllerName { get; set; }
}

@Html.MenuItem("Events", "Index", "Events", 
    new[] {
        new HyperlinkDataModel {
            ActionName = "FirstEvent", ControllerName = "Events", LinkText = "First Event" 
        }, 
        new HyperlinkDataModel {
            ActionName = "SecondEvent", ControllerName = "Events", LinkText = "Second Event"
        }
    })

Then do this in the HtmlHelper:

public static MvcHtmlString MenuItem(
this HtmlHelper htmlHelper,
string text,
string action,
string controller,
IList<HyperlinkDataModel> dropdown
)
{
    ...
    foreach (var item in dropdown)
    {
        var dropdownli = new TagBuilder("li");
        dropdownli.InnerHtml = htmlHelper.ActionLink(item.LinkText, item.ActionName,
            item.ControllerName, null, null).ToHtmlString();
        dropdownList.InnerHtml += dropdownli;
    }

Upvotes: 1

Related Questions