Привязка линейного списка к иерархическому виду дерева

#list #xaml #treeview

#Список #xaml #просмотр дерева

Вопрос:

 class MyItem
{
    public long ID;
    public string Name;
    public long? ParentID;

    public MyItem(long id, string name, long? parent)
    {
        ID = id;
        Name = name;
        ParentID= parent;
    }
}

List<MyItem> myItemList = new List<MyItem>();
myItemList.Add(new MyItem(1, "Item1", null));
myItemList.Add(new MyItem(2, "Item1", 1));
myItemList.Add(new MyItem(3, "Item1", 1));
myItemList.Add(new MyItem(4, "Item1", 5));
myItemList.Add(new MyItem(5, "Item1", null));
myItemList.Add(new MyItem(6, "Item1", 3));
myItemList.Add(new MyItem(7, "Item1", null));
  

Я хочу привязать myItemList к treeview WPF с помощью XAML, чтобы получить подобное представление.

 1

  |--2

  |--3

     |--6
5

  |--4

7
  

Ответ №1:

Вот как я это решил. Мне нужно иметь 2 класса:

1) LinqToObjectsExtensionMethods :

 using System;
using System.Collections.Generic;
using System.Linq;

namespace APTClient.Model
{
    static class LinqToObjectsExtensionMethods
    {
        private static IEnumerable<HierarchyNode<TEntity>> CreateHierarchy<TEntity, TProperty>(IEnumerable<TEntity> allItems, TEntity parentItem, Func<TEntity, TProperty> idProperty,
                                                                                           Func<TEntity, TProperty> parentIdProperty, object rootItemId, int maxDepth, int depth)
                                                                                          where TEntity : class
    {
        IEnumerable<TEntity> childs;
        if (rootItemId != null)
        {
            childs = allItems.Where(i => idProperty(i).Equals(rootItemId));
        }
        else
        {
            if (parentItem == null)
            {
                childs = allItems.Where(i => parentIdProperty(i).Equals(default(TProperty)));
            }
            else
            {
                childs = allItems.Where(i => parentIdProperty(i).Equals(idProperty(parentItem)));
            }
        }
        if (childs.Count() > 0)
        {
            depth  ;
            if ((depth <= maxDepth) || (maxDepth == 0))
            {
                foreach (var item in childs)
                    yield return
                    new HierarchyNode<TEntity>()
                    {
                        Entity = item,
                        ChildNodes =
                        CreateHierarchy(allItems.AsEnumerable(), item, idProperty, parentIdProperty, null, maxDepth, depth),
                        Depth = depth,
                        Parent = parentItem
                    };
            }
        }
    }
    /// <summary>
    /// LINQ to Objects (IEnumerable) AsHierachy() extension method
    /// </summary>
    /// <typeparam name="TEntity">Entity class</typeparam>
    /// <typeparam name="TProperty">Property of entity class</typeparam>
    /// <param name="allItems">Flat collection of entities</param>
    /// <param name="idProperty">Func delegete to Id/Key of entity</param>
    /// <param name="parentIdProperty">Func delegete to parent Id/Key</param>
    /// <returns>Hierarchical structure of entities</returns>
    public static IEnumerable<HierarchyNode<TEntity>> AsHierarchy<TEntity, TProperty>(this IEnumerable<TEntity> allItems, Func<TEntity, TProperty> idProperty
                                                                                    , Func<TEntity, TProperty> parentIdProperty) where TEntity : class
    {
        return CreateHierarchy(allItems, default(TEntity), idProperty, parentIdProperty, null, 0, 0);
    }
    /// <summary>
    /// LINQ to Objects (IEnumerable) AsHierachy() extension method
    /// </summary>
    /// <typeparam name="TEntity">Entity class</typeparam>
    /// <typeparam name="TProperty">Property of entity class</typeparam>
    /// <param name="allItems">Flat collection of entities</param>
    /// <param name="idProperty">Func delegete to Id/Key of entity</param>
    /// <param name="parentIdProperty">Func delegete to parent Id/Key</param>
    /// <param name="rootItemId">Value of root item Id/Key</param>
    /// <returns>Hierarchical structure of entities</returns>
    public static IEnumerable<HierarchyNode<TEntity>> AsHierarchy<TEntity, TProperty>(this IEnumerable<TEntity> allItems, Func<TEntity, TProperty> idProperty
                                                                                    , Func<TEntity, TProperty> parentIdProperty, object rootItemId) where TEntity : class
    {
        return CreateHierarchy(allItems, default(TEntity), idProperty, parentIdProperty, rootItemId, 0, 0);
    }
    /// <summary>
    /// LINQ to Objects (IEnumerable) AsHierachy() extension method
    /// </summary>
    /// <typeparam name="TEntity">Entity class</typeparam>
    /// <typeparam name="TProperty">Property of entity class</typeparam>
    /// <param name="allItems">Flat collection of entities</param>
    /// <param name="idProperty">Func delegete to Id/Key of entity</param>
    /// <param name="parentIdProperty">Func delegete to parent Id/Key</param>
    /// <param name="rootItemId">Value of root item Id/Key</param>
    /// <param name="maxDepth">Maximum depth of tree</param>
    /// <returns>Hierarchical structure of entities</returns>
    public static IEnumerable<HierarchyNode<TEntity>> AsHierarchy<TEntity, TProperty>(this IEnumerable<TEntity> allItems, Func<TEntity, TProperty> idProperty
                                                                                    , Func<TEntity, TProperty> parentIdProperty, object rootItemId, int maxDepth) where TEntity : class
    {
        return CreateHierarchy(allItems, default(TEntity), idProperty, parentIdProperty, rootItemId, maxDepth, 0);
    }
}}
  

2) HierarchyNode<T> :

 using System.Collections.Generic;

namespace APTClient.Model
{
    public class HierarchyNode<T> where T : class
    {
        public T Entity { get; set; }
        public IEnumerable<HierarchyNode<T>> ChildNodes { get; set; }
        public int Depth { get; set; }
        public T Parent { get; set; }
    }
}
  

У меня есть List<MyItem> myItemList;

 List<MyItem> myItemList = new List<MyItem>(); 
myItemList.Add(new MyItem(1, "Item1", null)); 
myItemList.Add(new MyItem(2, "Item1", 1)); 
myItemList.Add(new MyItem(3, "Item1", 1)); 
myItemList.Add(new MyItem(4, "Item1", 5)); 
myItemList.Add(new MyItem(5, "Item1", null)); 
myItemList.Add(new MyItem(6, "Item1", 3)); 
myItemList.Add(new MyItem(7, "Item1", null)); 
  

Затем

 List<HierarchyNode<MyItem>> = myItemList.AsHierarchy(m => m.ID, m => m.ParentID);