2010-01-20 2 views
4

У меня есть список, который выглядит следующим образом:WPF - хороший способ, чтобы взять список Дерева

 
Base/Level1/Item1 
Base/Level1/Item2 
Base/Level1/Sub1/Item1 
Base/Level2/Item1 
Base/Level3/Sub1/Item1 

Я хотел бы простой способ положить, что в ListView. (Т.е. похоже на это)

 
Base 
    | 
    +->Level1 
    | | 
    | +=Item1 
    | +=Item2 
    | | 
    | +->Sub1 
    |  | 
    |  +=Item1 
    | 
    +->Level2 
    | | 
    | +=Item1 

    | 
    +->Level3 
     | 
     +->Sub1 
      | 
      +=Item1 

Есть ли установленный способ сделать этот вид преобразования или мне просто нужно свернуть свой собственный парсер?

(В случае, если это может иметь отношение реальных деталей в моем коде TFS Итерационного Paths.)

+0

Вы говорите, что у вас нет иерархической структуры данных? просто плоский список? –

+0

Ну, я беру его в список из XML-структуры, которая не поддается пониманию. Так что да, у меня есть плоский список. (Подумайте об этом списке путей к файлам, которые я хочу показать в TreeView) – Vaccano

ответ

5

Это будет принимать список строк и превратить его в дерево, подходящее для просмотра с TreeView как вы описали:

public IList BuildTree(IEnumerable<string> strings) 
{ 
    return 
    from s in strings 
    let split = s.Split("/") 
    group s by s.Split("/")[0] into g // Group by first component (before /) 
    select new 
    { 
     Name = g.Key, 
     Children = BuildTree(   // Recursively build children 
     from s in grp 
     where s.Length > g.Key.Length+1 
     select s.Substring(g.Key.Length+1)) // Select remaining components 
    }; 
} 

Это вернет дерево анонимных типов, каждое из которых содержит свойство Name и свойство Children. Это можно связать непосредственно с TreeView, указав HierarchicalDataTemplate с ItemsSource="{Binding Children}" и содержимым, состоящим из <TextBlock Text="{Binding Name}"> или аналогичного.

В качестве альтернативы вы можете определить класс узла дерева в коде, если вам нужны дополнительные члены или семантика. Например, если этот класс узла:

public class Node 
{ 
    public string Name { get; set; } 
    public List<Node> Children { get; set; } 
} 

ваша функция BuildTree будет немного отличаться:

public List<Node> BuildTree(IEnumerable<string> strings) 
{ 
    return (
    from s in strings 
    let split = s.Split("/") 
    group s by s.Split("/")[0] into g // Group by first component (before /) 
    select new Node 
    { 
     Value = g.Key, 
     Children = BuildTree(   // Recursively build children 
     from s in grp 
     where s.Length > g.Key.Length+1 
     select s.Substring(g.Key.Length+1)) // Select remaining components 
    } 
    ).ToList(); 
} 

Опять же это может быть связано непосредственно с помощью HierarchicalDataTemplate. Обычно я использую первое решение (анонимные типы), если я не хочу делать что-то особенное с узлами дерева.

2

МОФ TreeView может отображать иерархические данные с помощью HierarchicalDataTemplates. Однако в настоящее время ваши данные плоские, поэтому вам придется преобразовать их в иерархическую структуру данных. Там нет встроенного способа сделать это для вас ...

Например, вы можете создать класс вроде этого:

class Node 
{ 
    public string Name { get; set; } 
    public List<Node> Children { get; set; } 
} 

Разбираем плоских данных в список Node объектов с подузлами, и создать TreeView со следующим HierarchicalDataTemplate в ресурсах:

<TreeView ItemsSource="{Binding ListOfNodes}"> 
    <TreeView.Resources> 
    <HierarchicalDataTemplate DataType="{x:Type local:Node}" ItemsSource="{Binding Children}"> 
     <TextBlock Text="{Binding Name}" /> 
    </HierarchicalDataTemplate> 
    </TreeView.Resources> 
</TreeView> 

дерево узлов будет автоматически генерируется на основе ваших данных. Если вам нужны различные классы для различных уровней иерархии, создавать различные HierarchicalDataTemplate для каждого класса

1

Более общая реализация может быть такой. Представьте себе Node класс, определяемый как:

public class Node<TItem, TKey> 
{ 
    public TKey Key { get; set; } 
    public int Level { get; set; } 
    public IEnumerable<TItem> Data { get; set; } 
    public List<Node<TItem, TKey>> Children { get; set; } 
} 

и два общих методы IEnumerable<T> расширения:

public static List<Node<TItem, TKey>> ToTree<TItem, TKey>(this IEnumerable<TItem> list, params Func<TItem, TKey>[] keySelectors) 
{ 
    return list.ToTree(0, keySelectors); 
} 

public static List<Node<TItem, TKey>> ToTree<TItem, TKey>(this IEnumerable<TItem> list, int nestingLevel, params Func<TItem, TKey>[] keySelectors) 
{ 
    Stack<Func<TItem, TKey>> stackSelectors = new Stack<Func<TItem, TKey>>(keySelectors.Reverse()); 
    if (stackSelectors.Any()) 
    { 
     return list 
      .GroupBy(stackSelectors.Pop()) 
      .Select(x => new Node<TItem, TKey>() 
      { 
       Key = x.Key, 
       Level = nestingLevel, 
       Data = x.ToList(), 
       Children = x.ToList().ToTree(nestingLevel + 1, stackSelectors.ToArray()) 
      }) 
      .ToList(); 
     } 
     else 
     { 
      return null; 
     } 

Вы можете использовать эти методы, чтобы агрегировать плоский список пользовательских объектов в виде дерева, с произвольным уровнем агрегации и более элегантный синтаксис. Единственное ограничение состоит в том, что ключи агрегации должны быть одного типа.

Пример:

class A 
{ 
    public int a { get;set; } 
    public int b { get;set; } 
    public int c { get;set; } 
    public int d { get;set; } 
    public string s { get;set; } 

    public A(int _a, int _b, int _c, int _d, string _s) 
    { 
     a = _a; 
     b = _b; 
     c = _c; 
     d = _d; 
     s = _s;  
    } 
} 

void Main() 
{ 
    A[] ls = { 
     new A(0,2,1,10,"one"), 
     new A(0,1,1,11,"two"), 
     new A(0,0,2,12,"three"), 
     new A(0,2,2,13,"four"), 
     new A(0,0,3,14,"five"), 
     new A(1,0,3,15,"six"), 
     new A(1,1,4,16,"se7en"), 
     new A(1,0,4,17,"eight"), 
     new A(1,1,5,18,"nine"), 
     new A(1,2,5,19,"dunno") 
    }; 

    var tree = ls.ToTree(x => x.a, x => x.b, x => x.c, x => x.d); 

} 

Примечание: Эта реализация не является «реальным» дерево, так как нет ни одного корневого узла, но вы можете реализовать класс в Tree<TItem, TKey> оболочке довольно легко.

HTH

Смежные вопросы