rellenar treeview de la lista de rutas de archivo en wpf


Hay varios ejemplos de cómo rellenar una vista en árbol a partir de una colección de rutas de archivo como this o this other example. Parece que no puedo encontrar tal ejemplo para WPF. Sé que puedo integrar windows forms y usar un control diferente para que funcione, pero sería bueno si pudiera hacer lo mismo con un control wpf treeview. La vista de árbol que quiero construir consta de unos 50.000 archivos, por lo que creo que será mejor si se enlaza a algo. Pero antes de vincularlo, creo que será útil construir uno basado en una Lista de cadenas (cadenas contiene las rutas de los archivos).

Author: Community, 2011-06-20

2 answers

Estaba intrigado por la pregunta y lo mezclé. Como primer paso creo que estoy bastante cerca de lo que estás buscando. Sin embargo, hablar de 50,000 artículos me hace pensar que la carga lenta puede ser apropiada. De todos modos, aquí está la versión simple basada en un artículo de Josh Smith. Puse todo el código aquí, pero la magia realmente tiene lugar con las plantillas de datos.

Se le han dado algunas clases para representar los objetos que estamos trabajando con...

using System.Collections.Generic;

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

Y...

namespace WpfTreeViewBinding.Model
{
    public class FileItem : Item
    {

    }
}

Y...

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

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

He creado un método recursivo para cargar algunos directorios/archivos...

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

A partir de ahí es solo cuestión de obtener los datos...

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

Y mostrándolo...

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

Toda la magia realmente sucede con las plantillas de datos. Supongo que la clave de todo esto es usar la HierarchicalDataTemplate para cualquier elemento con jerarquía (es decir, directorios).

NOTA 1: No he probado extensamente este. No ha sido perfilado para el rendimiento. Sin embargo, agradecería cualquier comentario, ya que este es un problema que traté de resolver hace mucho tiempo y me di por vencido. ¡Gracias!

NOTA 2: Tendrá que establecer la ruta de acceso codificada a algo que tenga sentido en su sistema.

Aquí hay una captura de pantalla que muestra directorios y archivos en diferentes niveles...

introduzca la descripción de la imagen aquí

 55
Author: John Laffoon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-07-03 04:05:38

Pequeña extensión para la solución anterior: He añadido código xaml para soportar los iconos, y soporte para cambiar entre los iconos de la carpeta abierta y cerrada:

 <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>
 3
Author: Mr.B,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-06-27 13:51:02