2011-06-20 13 views
23

Istnieje kilka przykładów sposobu wypełniania widoku drzewa z kolekcji ścieżek plików, takich jak this lub this other przykład. Nie mogę znaleźć takiego przykładu dla WPF. Wiem, że mogę zintegrować formularze okien i użyć innej kontrolki, aby to działało, ale będzie miło, gdybym mógł zrobić to samo z kontrolą drzewa wpf. Widok drzewa, który chcę zbudować, składa się z około 50 000 plików, dlatego myślę, że będzie lepiej, jeśli jest powiązany z czymś. Ale najpierw przed związaniem go, myślę, że będzie pomocne zbudowanie go na podstawie listy łańcuchów (łańcuchy zawierają ścieżki plików).Wypełnij widok drzewa z listy ścieżek plików w wpf

+1

Nie musisz najpierw wypełniać całej kolekcji. Możesz mieć kontrolę nad drzewem na żądanie. Używałem do tego kontroli drzewa teleriksów. –

Odpowiedz

53

Zaintrygowało mnie pytanie i zrzuciłem to razem. W pierwszym przejściu uważam, że jestem blisko tego, czego szukasz. Mówienie o 50 000 przedmiotach sprawia jednak, że myślę, że leniwy załadunek może być właściwy. Tak czy inaczej, oto prosta wersja oparta na article autorstwa Josha Smitha. Umieściłem tutaj cały kod, ale magia naprawdę ma miejsce w szablonach danych.

Biorąc kilka klas do reprezentowania obiektów, nad którymi pracujemy z ...

using System.Collections.Generic; 

namespace WpfTreeViewBinding.Model 
{ 
    public class Item 
    { 
     public string Name { get; set; } 
     public string Path { get; set; } 
    } 
} 

i ...

namespace WpfTreeViewBinding.Model 
{ 
    public class FileItem : Item 
    { 

    } 
} 

i ...

namespace WpfTreeViewBinding.Model 
{ 
    public class DirectoryItem : Item 
    { 
     public List<Item> Items { get; set; } 

     public DirectoryItem() 
     { 
      Items = new List<Item>(); 
     } 
    } 
} 

I utworzono rekurencyjną metodę ładowania niektórych katalogów/plików ...

using System.Collections.Generic; 
using System.IO; 
using WpfTreeViewBinding.Model; 

namespace WpfTreeViewBinding 
{ 
    public class ItemProvider 
    { 
     public List<Item> GetItems(string path) 
     { 
      var items = new List<Item>(); 

      var dirInfo = new DirectoryInfo(path); 

      foreach(var directory in dirInfo.GetDirectories()) 
      { 
       var item = new DirectoryItem 
           { 
            Name = directory.Name, 
            Path = directory.FullName, 
            Items = GetItems(directory.FullName) 
           }; 

       items.Add(item); 
      } 

      foreach(var file in dirInfo.GetFiles()) 
      { 
       var item = new FileItem 
           { 
            Name = file.Name, 
            Path = file.FullName 
           }; 

       items.Add(item); 
      } 

      return items; 
     } 
    } 
} 

Stamtąd to tylko kwestia uzyskania danych ...

using System.Windows; 

namespace WpfTreeViewBinding 
{ 
    /// <summary> 
    /// Interaction logic for MainWindow.xaml 
    /// </summary> 
    public partial class MainWindow : Window 
    { 
     public MainWindow() 
     { 
      InitializeComponent(); 

      var itemProvider = new ItemProvider(); 

      var items = itemProvider.GetItems("C:\\Temp"); 

      DataContext = items; 
     } 
    } 
} 

i wyświetlanie go ...

<Window x:Class="WpfTreeViewBinding.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:Model="clr-namespace:WpfTreeViewBinding.Model" 
     Title="MainWindow" 
     Height="350" Width="525"> 

    <Window.Resources> 

     <HierarchicalDataTemplate DataType="{x:Type Model:DirectoryItem}" 
            ItemsSource="{Binding Items}"> 
      <TextBlock Text="{Binding Path=Name}" ToolTip="{Binding Path=Path}" /> 
     </HierarchicalDataTemplate> 

     <DataTemplate DataType="{x:Type Model:FileItem}"> 
      <TextBlock Text="{Binding Path=Name}" ToolTip="{Binding Path=Path}" /> 
     </DataTemplate> 

    </Window.Resources> 

    <Grid Margin="8"> 
     <TreeView ItemsSource="{Binding}" /> 
    </Grid> 

</Window> 

Cała magia naprawdę dzieje się z szablonów danych. Myślę, że kluczem do całości jest użycie HierarchicalDataTemplate dla dowolnych elementów z hierarchią (to jest katalogów).

UWAGA 1: Nie testowałem tego w dużym stopniu. Nie zostało sprofilowane pod względem wydajności. Byłbym wdzięczny za wszelkie uwagi, ponieważ jest to problem, który starałem się rozwiązać dawno temu i poddałem się. Dzięki!

UWAGA 2: Musisz ustawić zakodowaną ścieżkę na coś, co ma sens w twoim systemie.

Oto zrzut ekranu pokazujący katalogów i plików na różnych poziomach ...

enter image description here

+0

Jhon wielkie dzięki! Twoja odpowiedź wygląda świetnie. Z niecierpliwością czekam na przetestowanie twojego rozwiązania, kiedy wrócę jutro rano. Nie edytuj więcej ... Pozwól mi najpierw przetestować. –

+4

To jest dobra odpowiedź. Jednak nie ma potrzeby tworzenia klasy Item i FileItem. Można utworzyć lokalny DataTemplate dla obu systemów.IO DirectoryInfo i klasy FileInfo. –

+0

Teraz popraw to, aby użyć leniwego ładowania:] – cordialgerm

3

małe rozszerzenie do poprzedniego rozwiązania: dodałem kod XAML wspierania ikony i wsparcie dla przełączania pomiędzy ikony otworzył i zamknął folder:

<HierarchicalDataTemplate DataType="{x:Type viewModels:SourceControlDirecoryViewModel}" 
            ItemsSource="{Binding Items}"> 
      <Grid> 
       <Grid.ColumnDefinitions> 
        <ColumnDefinition Width="Auto" /> 
        <ColumnDefinition Width="5" /> 
        <ColumnDefinition Width="*" /> 
       </Grid.ColumnDefinitions> 
       <Image Width="16" 
         Height="16" 
         Source="{StaticResource ImageSourceFolderClosed16x16}" 
         x:Name="img" /> 
       <TextBlock Text="{Binding Path=Name}" 
          ToolTip="{Binding Path=Path}" 
          Grid.Column="2" /> 
      </Grid> 
      <DataTemplate.Triggers> 
       <DataTrigger Binding="{Binding IsExpanded, RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type TreeViewItem}}}" 
          Value="True"> 
        <Setter Property="Source" 
          TargetName="img" 
          Value="{StaticResource ImageSourceFolderOpened16x16}" /> 
       </DataTrigger> 
      </DataTemplate.Triggers> 
     </HierarchicalDataTemplate>