2009-11-10 6 views
2

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

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

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

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

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... 
} 

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

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

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

ответ

3

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

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

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

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

2

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

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

Это решение устраняет проблемы, указанные в качестве самостоятельного метода расширения содержал прочь 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); 
}