...

воскресенье, 22 декабря 2013 г.

[Из песочницы] Древовидный список на ASP.NET MVC 4

Добрый день! На хабре есть статья, в которой рассказывается как сделать древовидный список. Однако, в этой версии будет использован движок Razor, Entity Framework и др., а так же реализованы операции со списком. Данный вариант отличается простотой и быстротой реализации. Статья рассчитана на тех, кто уже знаком с ASP .NET MVC.

Возможности:



  • Отображение списка

  • Добавление элементов

  • Перемещение элементов

  • Удаление элементов




Используемые технологии:


  • Microsoft ASP. NET MVC 4

  • Entity Framework

  • Linq to Entity

  • Microsoft SQL Server (Local DB)






База данных




Так как все записи будут храниться в базе данных, то необходимо создать следующую таблицу:

public class News
{
public int Id {get;set;} //Идентификатор новости
public int? ParentId {get;set;} //Идентификатор родительской новости
public string Title {get;set;} //Заголовок новости
public bool IsDeleted {get;set;} //Флаг удаления
}




Модели




Далее создадим модели для работы:

1. Обычно в моделях не используют напрямую записи из базы данных, поэтому создадим модель похожую на таблицу.

public class NewsModel
{
public int Id {get;set;} //Идентификатор новости
public int? ParentId {get;set;} //Идентификатор родительской новости
public string Title {get;set;} //Заголовок новости
}




2. Список новостей.

public NewsListModel
{
public int? Seed {get;set;} //Корневой элемент
public IEnumerable<NewsModel> News {get;set;} //Список новостей
}




Контроллер



Ниже представлен контроллер, который умеет выбирать, удалять, добавлять и перемещать новости.

public class NewsController : Controller
{
public ActionResult Index()
{
using (NewsContext context = new NewsContext())
{
NewsListModel model = new NewsListModel()
{
News = context.News.Where(x => !x.IsDeleted).ToArray().Select(x => new NewsModel(x))
};
return View(model);
}
}

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Add(int? parentId, string title)
{
using (NewsContext context = new NewsContext())
{
var newNews = new News()
{
ParentId = parentId,
Title = title
};
context.News.Add(newNews);
context.SaveChanges();
}
return RedirectToAction("Index");
}

[ValidateAntiForgeryToken]
[HttpPost]
public ActionResult Move(int nodeId, int? newParentId)
{
if (nodeId == newParentId)
{
return RedirectToAction("Index");
}
using (NewsContext context = new NewsContext())
{
if (newParentId.HasValue && ContainsChilds(context, nodeId, newParentId.Value))
{
return RedirectToAction("Index");
}
var node = context.News.Where(x => x.Id == nodeId).Single();
node.ParentId = newParentId;
context.SaveChanges();
}
return RedirectToAction("Index");
}

private bool ContainsChilds(NewsContext context, int parentId, int id)
{
bool result = false;
var inner = context.News.Where(x => x.ParentId == parentId && !x.IsDeleted).ToArray();
foreach (var node in inner)
{
if (node.Id == id && node.ParentId == parentId)
{
return true;
}
result = ContainsChilds(context, node.Id, id);
}
return result;
}

[HttpPost]
public ActionResult Delete(int id)
{
using (NewsContext context = new NewsContext())
{
DeleteNodes(context, id);
context.SaveChanges();
}

return RedirectToAction("Index");
}

private void DeleteNodes(NewsContext context, int id)
{
var inner = context.News.Where(x => x.ParentId == id && !x.IsDeleted).ToArray();
foreach (var node in inner)
{
node.IsDeleted = true;
DeleteNodes(context, node.Id);
}
var deleted = context.News.Where(x => x.Id == id && !x.IsDeleted).Single();
deleted.IsDeleted = true;
}
}




Представление




Как видно из кода, большинство методов выполняются рекурсивно. Рекурсия позволяет достаточно лаконично реализовать операции. Так же рекурсия используется при отображении на странице. Рассмотрим вывод древовидного списка.

_TreeList.cshtml



@model MySLOTree.Models.NewsListModel

@if (Model.News.Where(x => x.ParentId == Model.Seed).Any())
{
<ul>
@foreach (var node in Model.News)
{
if (node.ParentId == Model.Seed)
{
<a>@node.Title</a>
MySLOTree.Models.NewsListModel inner = new MySLOTree.Models.NewsListModel
{
Seed = node.Id,
News = Model.News
};
@Html.Partial("_TreeList", inner)
}
}
</ul>
}




Результат




Пустой список




Добавление элементов




Отображение списка




Сворачивание\Разворачивание списка




Перемещение элементов




Заключение




Для перемещения элементов в дереве используется drag and drop. Добавление и удаление элементов происходит путем нажатия соответствующих иконок. В статье опущены некоторые моменты. Все подробности можно увидеть в исходном коде.

Полный исходный код доступен на github.

P.S. С радостью отвечу на вопросы и обменяюсь опытом.


This entry passed through the Full-Text RSS service — if this is your content and you're reading it on someone else's site, please read the FAQ at fivefilters.org/content-only/faq.php#publishers.


Комментариев нет:

Отправить комментарий