Статьи

Написание свободного ASP.NET MVC Рекурсивный помощник TreeView

Этот пост является обновлением моего исходного ASP.NET MVC Recursive TreeView Helper почти 3 года назад. Как ни странно, это по-прежнему пост с высоким трафиком и около 50 комментариев, требующих обновления или полного решения для загрузки. Я подумал, что если я собираюсь сделать это, я мог бы также дать API крайне необходимый фейслифтинг и вставить его в NuGet.

Что это такое?

Учитывая следующую самореферентную иерархическую модель…

public class TreeViewLocation
{
    public TreeViewLocation()
    {
        ChildLocations = new HashSet<TreeViewLocation>();
    }
 
    public int Id { get; set; }
    public string Name { get; set; }
 
    public virtual int? ParentLocationId { get; set; }
         
    public virtual ICollection<TreeViewLocation> ChildLocations { get; set; }
}

 

… Мы хотим создать неупорядоченный список HTML, как этот

образ

как выглядит новый API?

Во-первых, извинения за смешивание подсветки синтаксиса. У моего по умолчанию еще нет отличной темы Razor.

Следующая Razor показывает API, который мы создадим. Он придерживается свободного синтаксиса, который многие разработчики предпочитают альтернативному (десятки перегрузок!). В конце концов, нам легче писать, легче расширять в будущем, и его легче обнаружить разработчикам, которые будут использовать его позже. Эта конкретная реализация TreeView также использует превосходный шаблонизатор HelperResult от Razor (синтаксис @ <text> показан ниже).

@model List<MvcTreeView.Models.Location>

@(Html.TreeView(Model)
    .EmptyContent("No locations have been defined yet!")    
    .Children(m => m.ChildLocations)
    .HtmlAttributes(new { id = "tree"})
    .ChildrenHtmlAttributes(new { @class = "subItem"})
    .ItemText(m => m.Name)
    .ItemTemplate(
        @<text>
            <a href="#@item.Id">@item.Name</a>
        </text>)
)

Как это было написано?

Определение свободного API

Написание свободного API, как правило, довольно просто. Ключевое требование заключается в том, чтобы каждый метод возвращал тип класса и всегда заканчивался словами «вернуть это»; Остальная часть тела метода обычно просто сохраняет некоторое состояние в закрытом поле, которое в конечном итоге будет использоваться для визуализации настроенного пользовательского интерфейса.

Например, чтобы установить ItemText, который будет отображать метку элемента в каждом <li>, мы берем селектор свойств и просто сохраняем его в поле _displayProperty, в конечном итоге возвращая текущий экземпляр, позволяющий объединить дальнейшие методы.

public TreeView<T> ItemText(Func<T, string> selector)
{
    if (selector == null) throw new ArgumentNullException("selector");
    _displayProperty = selector;
    return this;
}

 

Рендеринг / IHtmlString

Наконец, как только разработчик настроил, как именно должен отображаться TreeView, нам нужно вывести HTML.

Один из способов подключиться к этой инфраструктуре — реализовать как IHtmlString, так и переопределить ToString () . MVC проверит, реализуем ли мы IHtmlString и, если это так, вызовет ToHtmlString (), чтобы запустить рендеринг, который написан для просмотра.

Также обратите внимание на вызов ValidateSettings () — это необходимо во многих гибких конфигурациях, поскольку такие API-интерфейсы иногда допускают неверную конфигурацию. Например, используя 2 несовместимых метода, таких как ItemText () и ItemTemplate () вместе — обычно вы либо хотите использовать простое текстовое отображение или полноразмерное отображение шаблона — но невозможно использовать оба. Мы могли бы выбросить исключение, предупреждая разработчика о том, что это неверная конфигурация.

public override string ToString()
{
    ValidateSettings();
 
    var listItems = _items.ToList();
 
    var ul = new TagBuilder("ul");
    ul.MergeAttributes(_htmlAttributes);
 
    // snip...
    return ul.ToString();
}
 
public string ToHtmlString()
{
    return ToString();
}

 

Получить код

Этот помощник очень легко добавить в ваш проект с помощью NuGet. В качестве альтернативы вы все равно можете пойти по ручному маршруту и ​​получить код из CodePlex.

NuGet / Образец пакета NuGet

В этот проект я решил включить образец пакета NuGet, который используется для простой демонстрации использования помощника.

Это пакеты только для исходного кода. Установив этот пакет в свой проект, вы получите необработанный файл в Helpers \ TreeView.cs, который вы можете редактировать или обновлять по своему усмотрению.

образ

В примере проекта используется та же концепция, он добавляет TreeViewController и представление TreeView.cshtml, которое демонстрирует использование помощника TreeView. После того, как вы опробовали пример и поиграли с ним, очень легко удалить его через NuGet, чтобы удалить ненужные файлы.

образ

CodePlex

И, конечно же, полный исходный код доступен для скачивания на CodePlex.

http://mvctreeview.codeplex.com

Просмотрите последний исходный код