WPF Heirachical DataTemplate в TreeView - PullRequest
       14

WPF Heirachical DataTemplate в TreeView

1 голос
/ 03 декабря 2010

Я пытаюсь разобраться с Heirarchical DataTemplates и TreeViews в WPF, и у меня возникли некоторые проблемы.

Я создал приложение только с TreeView в форме, как показано ниже, и определил HierarchicalDataTemplate как для объекта Directory, так и для объекта File. Затем я привязал TreeView к свойству Directories (ObservableCollection) моей модели.

<Grid>
        <Grid.Resources>

            <HierarchicalDataTemplate DataType="{x:Type local:Directory}" ItemsSource ="{Binding Directories}">
                <TextBlock Text="{Binding Path=Name}"/>
            </HierarchicalDataTemplate>
            <HierarchicalDataTemplate DataType="{x:Type local:File}" ItemsSource ="{Binding Files}">
                <TextBlock Text="{Binding Path=FileName}"/>
            </HierarchicalDataTemplate>
        </Grid.Resources>
        <TreeView Margin="12,12,0,12" Name="treeView1" HorizontalAlignment="Left" Width="204" >
            <TreeViewItem ItemsSource="{Binding Directories}" Header="Folder Structure" />
        </TreeView>
    </Grid>

Это работает в том, что в TreeView я вижу свои каталоги, и он рекурсивно отображает все подкаталоги, но я хочу видеть каталоги и файлы! Я проверил модель, и она определенно содержит файлы в некоторых подкаталогах, но я не вижу их в дереве.

Я не уверен, что это мой шаблон или проблема, поэтому я включил их все! : -)

Спасибо

OneShot

public partial class MainWindow : Window
{

    public MainWindow()
    {
        InitializeComponent();

    }


    private MainWindowViewModel _vm;

    public MainWindowViewModel VM
    {
        set
        {
            _vm = value;
            this.DataContext = _vm;
        }
    }

    private void Window_Loaded(object sender, RoutedEventArgs e)
    {
        var d = new Directory() { Name = "temp" };
        recurseDir("c:\\temp", ref d);

        VM = new MainWindowViewModel( new List<Directory>() { d } );            
    }

    private void recurseDir(string path, ref Directory dir)
    {
        var files = System.IO.Directory.GetFiles(path);
        var dirs = System.IO.Directory.GetDirectories(path);

        dir.Name = path.Substring(path.LastIndexOf("\\")+1);

        for (int i = 0; i < files.Length; i++)
        {
            var fi = new FileInfo(files[i]);
            dir.Files.Add(new File() { 
                FileName = System.IO.Path.GetFileName(files[i]), 
                DirectoryPath = System.IO.Path.GetDirectoryName(files[i]), 
                Size = fi.Length, 
                Extension= System.IO.Path.GetExtension(files[i]) 
            });

        }

        for (int i = 0; i < dirs.Length; i++)
        {
            var d = new Directory() { Name = dirs[i].Substring(dirs[i].LastIndexOf("\\")+1) };
            recurseDir(dirs[i], ref d);
            dir.Directories.Add(d);

        }

    }
}

-

 public class MainWindowViewModel
        : DependencyObject
    {


        public MainWindowViewModel(List<Directory> Dirs)
        {
            this.Directories = new ObservableCollection<Directory>( Dirs);
        }

        public ObservableCollection<Directory> Directories
        {
            get { return (ObservableCollection<Directory>)GetValue(DirectoriesProperty); }
            set { SetValue(DirectoriesProperty, value); }
        }

        public static readonly DependencyProperty DirectoriesProperty =
            DependencyProperty.Register("Directories", typeof(ObservableCollection<Directory>), typeof(MainWindowViewModel), new UIPropertyMetadata(null));

        public Directory BaseDir
        {
            get { return (Directory)GetValue(BaseDirProperty); }
            set { SetValue(BaseDirProperty, value); }
        }

        public static readonly DependencyProperty BaseDirProperty =
            DependencyProperty.Register("BaseDir", typeof(Directory), typeof(MainWindowViewModel), new UIPropertyMetadata(null));


    }

-

public class Directory
    {
        public Directory()
        {
            Files = new List<File>();
            Directories = new List<Directory>();
        }
        public List<File> Files { get; private set; }
        public List<Directory> Directories { get; private set; }
        public string Name { get; set; }
        public int FileCount
        {
            get
            {
                return Files.Count;
            }
        }
        public int DirectoryCount
        {
            get
            {
                return Directories.Count;
            }
        }
        public override string ToString()
        {
            return Name;
        }
    }

-

public class File
    {
        public string DirectoryPath { get; set; }
        public string FileName { get; set; }
        public string Extension { get; set; }
        public double Size { get; set; }
        public string FullPath
        {
            get
            {
                return System.IO.Path.Combine(DirectoryPath, FileName);
            }
        }
        public override string ToString()
        {
            return FileName;
        }
    }

1 Ответ

2 голосов
/ 03 декабря 2010

Взгляните на это еще раз:

        <HierarchicalDataTemplate DataType="{x:Type local:Directory}" ItemsSource ="{Binding Directories}">
            <TextBlock Text="{Binding Path=Name}"/>
        </HierarchicalDataTemplate>
        <HierarchicalDataTemplate DataType="{x:Type local:File}" ItemsSource ="{Binding Files}">
            <TextBlock Text="{Binding Path=FileName}"/>
        </HierarchicalDataTemplate>

То, что вы говорите, это то, что если вы встретите объект типа File, отобразите его с помощью текстового блока и получите его дочерние элементы из свойства Files в File. То, что вы действительно хотите, чтобы файлы отображались в каждом каталоге, поэтому вы должны создать новое свойство, которое отображает как каталоги, так и файлы:

public class Directory
{
    //...
    public IEnumerable<Object> Members
    {
        get
        {
            foreach (var directory in Directories)
                yield return directory;

            foreach (var file in Files)
                yield return file;
        }
    }
    //...
}

и тогда ваш шаблон становится:

    <HierarchicalDataTemplate DataType="{x:Type local:Directory}" ItemsSource ="{Binding Members}">
        <TextBlock Text="{Binding Path=Name}"/>
    </HierarchicalDataTemplate>
    <DataTemplate DataType="{x:Type local:File}">
        <TextBlock Text="{Binding Path=FileName}"/>
    </DataTemplate>

UPDATE:

На самом деле, вышесказанного недостаточно, если вы хотите получать уведомления об изменениях коллекции для Участников. В этом случае я рекомендую создать новую коллекцию ObservableCollection и добавить в нее записи каталога и файла параллельно с добавлением в коллекции файлов и каталогов.

Кроме того, вы можете пересмотреть способ хранения вашей информации и поместить все в одну коллекцию. Остальные списки - это просто отфильтрованные представления основной коллекции.

...