Сравните два экземпляра RouteValueDictionary - PullRequest
2 голосов
/ 11 ноября 2009

Я пишу помощника для моего приложения, который записывает пункт меню для данного строго типизированного контроллера / действия следующим образом:

<%= Html.MenuLink<WhateverController>(c => c.WhateverAction(), "Whatever") %>

В рамках этого процесса я хотел бы применить класс active к выводимой ссылке, если текущая страница и ссылка на нее совпадают. Я полагаю, что лучший способ сделать это - сравнить содержимое RouteValueDictionary для текущего запроса с результатом выражения, переданного вспомогательному методу. Однако я не могу найти хороший способ сравнить, совпадают ли пункты в двух RouteValueDictionary с.

Есть ли простой способ сделать это? Я действительно хочу завершить это следующим образом:

public static string MenuLink<T>(this HtmlHelper html, Expression<Action<T>> action, string linkText) where T : Controller
{
    // var link = html.ActionLink<T>(action, linkText, new {}); // Not important yet

    var routeValues = Microsoft.Web.Mvc.Internal.ExpressionHelper.GetRouteValuesFromExpression<T>(action);  // Might change?
    var currentRouteVals = html.ViewContext.RouteData.Values;
    bool isActivePage = /* are the contents of routeValues also 
                           inside currentRouteValues? */

    var tb = new TagBuilder("li");
    // Continues...
}

Я попытался использовать встроенное сравнение (==), но кажется, что оно использует реализацию равенства по умолчанию и поэтому возвращает false, поскольку они не являются одним и тем же экземпляром. Я также попробовал следующее:

bool isActivePage = routeValues.All(x => currentRouteVals.ContainsValue(x));

но это тоже не работает. Я полностью лаю не на том дереве?

Ответы [ 2 ]

3 голосов
/ 11 ноября 2009

Бах, я отправляю вопрос, а потом выясняю ответ. Я пишу здесь на случай, если кто-то еще сталкивается с этой проблемой. Строка, в которой я нуждался, была следующей:

bool isActivePage = routeValues.All(x => x.Value.ToString() == (currentRouteVals[x.Key].ToString()));

Оказывается, изначально они сравнивались как объекты, а не как строки. Преобразование их в строки сравнивает их, как можно было бы надеяться, и теперь все хорошо.

Следует отметить, что их следует сравнивать примерно так. Если они сравниваются другим способом, RouteValueDictionary может содержать вещи, отличные от тех, которые вас интересуют (например, значение «id»). Или, по крайней мере, сейчас я так понимаю. Дальнейшие эксперименты могут потребовать от меня повторного посещения этого ...

2 голосов
/ 12 июня 2012

Я только что столкнулся с той же проблемой, смотрел на принятый ответ и заметил, что это будет:

  • вызвать исключение, если ключ не существует во втором списке routeValues ​​
  • чувствителен к регистру, что обычно не относится к URI Microsoft.
  • если ключ находится во втором списке, но не в первом, списки сравниваются как одинаковые, что неверно.

Это решение решает указанные проблемы как автономный метод расширения из RouteValueDictionary:

public static bool AreEqual(this RouteValueDictionary rvdA, RouteValueDictionary rvdB)
{
    var Equal = 
        new Func<RouteValueDictionary, RouteValueDictionary, bool>((a, b) => a.All(kvp =>
       {
           object val = b[kvp.Key];
           return val != null && kvp.Value.ToString().Equals(val.ToString(), StringComparison.InvariantCultureIgnoreCase);
       }));                                                 

    return rvdA.Count == rvdB.Count && Equal(rvdA, rvdB) && Equal(rvdB, rvdA);
}   
...