заполнить древовидную структуру из списка путей к файлам в wpf - PullRequest
26 голосов
/ 20 июня 2011

Существует несколько примеров заполнения древовидного представления из набора путей к файлам, например этот или этот другой пример.Я не могу найти такой пример для WPF.Я знаю, что могу интегрировать формы Windows и использовать другой элемент управления, чтобы заставить его работать, но было бы хорошо, если бы я мог сделать то же самое с элементом управления wpf treeview.Древовидное представление, которое я хочу построить, состоит из около 50 000 файлов, поэтому я думаю, что будет лучше, если оно будет привязано к чему-либо.Но сначала, прежде чем связать его, я думаю, что будет полезно создать его на основе списка строк (строки содержат пути к файлам).

Ответы [ 2 ]

60 голосов
/ 03 июля 2011

Я был заинтригован вопросом и бросил это вместе. В качестве первого прохода я думаю, что я довольно близок к тому, что вы ищете. Разговоры о 50000 предметов заставляют меня думать, что ленивая загрузка может быть уместной. В любом случае, вот простая версия, основанная на статье Джоша Смита. Я поместил весь код здесь, но волшебство действительно происходит с шаблонами данных.

Учитывая несколько классов для представления объектов, с которыми мы работаем ...

using System.Collections.Generic;

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

и ...

namespace WpfTreeViewBinding.Model
{
    public class FileItem : Item
    {

    }
}

и ...

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

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

Я создал рекурсивный метод для загрузки некоторых каталогов / файлов ...

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;
        }
    }
}

Оттуда это просто вопрос получения данных ...

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;
        }
    }
}

И отображение его ...

<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>

Вся магия действительно происходит с шаблонами данных. Я предполагаю, что ключ ко всему этому - использование HierarchicalDataTemplate для любых элементов с иерархией (то есть каталогов).

ПРИМЕЧАНИЕ 1. Я не проверял это подробно. Он не был профилирован для исполнения. Я хотел бы получить любую обратную связь, так как это проблема, которую я пытался решить давным-давно и отказался. Спасибо!

ПРИМЕЧАНИЕ 2. Вам нужно будет указать жестко заданный путь, который будет иметь смысл в вашей системе.

Вот скриншот, показывающий каталоги и файлы на разных уровнях ...

enter image description here

3 голосов
/ 27 июня 2016

Небольшое расширение для предыдущего решения: Я добавил код xaml для поддержки значков и поддержки переключения между значками для открытой и закрытой папки:

 <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>
...