Hallo zusammen.
Ich beschäftige mich ja in letzter Zeit ein wenig mit WPF. Einfach Bindings bekomme ich inzwischen recht gut hin und MVVM hab ich soweit denke ich auch verstanden.
Jetzt wollte ich mich aber mal an ein paar komplexere Sachen ranwagen und hab mir deshalb ein kleines Testprojekt angelegt. Ziel soll es ein einen ganz einfachen Explorer-Verschnitt zu erstellen, also links ein Treeview mit den Ordnern und rechts dann ein ListView für die Dateien.
Ich hab mir auch schon ein Model erstellt, welches so aussieht:
Spoiler anzeigen
Und ein passendes ViewModel hab ich auch schon:
Spoiler anzeigen
Das ViewModel ist dem MainWindow bereits als DataContext zugewiesen.
Mein Problem ist jetzt der XAML-Code. Alles, was ich bis jetzt geschafft habe, ist das hier:
Spoiler anzeigen
So werden mir schonmal die Laufwerke angezeigt, auch mit dem Dummyknoten darin. Allerdings habe ich Probleme, darauf zu reagieren, wenn ein Knoten erweitert wurde. Ich möchte die Expanded-Eigenschaft jedes TreeViewItems an die Expanded-Eigenschaft des zugehörigen FileSystemTreeViewItem-Objekts binden, ich weiß aber nicht wie.
Hat da jemand ne Idee? Kann doch eigentlich nicht so schwer sein.
Ich beschäftige mich ja in letzter Zeit ein wenig mit WPF. Einfach Bindings bekomme ich inzwischen recht gut hin und MVVM hab ich soweit denke ich auch verstanden.
Jetzt wollte ich mich aber mal an ein paar komplexere Sachen ranwagen und hab mir deshalb ein kleines Testprojekt angelegt. Ziel soll es ein einen ganz einfachen Explorer-Verschnitt zu erstellen, also links ein Treeview mit den Ordnern und rechts dann ein ListView für die Dateien.
Ich hab mir auch schon ein Model erstellt, welches so aussieht:
C-Quellcode
- namespace SimpleExplorer
- {
- public abstract class FileSystemTreeViewItem : INotifyPropertyChanged
- {
- bool expanded;
- FileSystemTreeViewItem[] childItems;
- public bool Expanded
- {
- get
- {
- return expanded;
- }
- set
- {
- expanded = value;
- if (value) OnExpand();
- }
- }
- public abstract DirectoryInfo Directory { get; }
- public FileSystemTreeViewItem[] ChildItems
- {
- get
- {
- return childItems;
- }
- protected set
- {
- childItems = value;
- if (PropertyChanged != null)
- PropertyChanged(this, new PropertyChangedEventArgs("ChildItems"));
- }
- }
- protected abstract void OnExpand();
- public event PropertyChangedEventHandler PropertyChanged;
- }
- public class DriveTreeViewItem : FileSystemTreeViewItem
- {
- DriveInfo drive;
- DirectoryInfo directory;
- public static DriveTreeViewItem[] GetDrives()
- {
- return DriveInfo.GetDrives().Select(item => new DriveTreeViewItem(item)).ToArray();
- }
- private DriveTreeViewItem(DriveInfo drive)
- {
- this.drive = drive;
- directory = drive.RootDirectory;
- ChildItems = new[] { new EmptyTreeViewItem() };
- }
- public override DirectoryInfo Directory
- {
- get { return directory; }
- }
- protected override void OnExpand()
- {
- if (drive.IsReady)
- ChildItems = directory.EnumerateDirectories().Select(item => new DirectoryTreeViewItem(item)).ToArray();
- else
- ChildItems = new FileSystemTreeViewItem[0];
- }
- }
- public class DirectoryTreeViewItem : FileSystemTreeViewItem
- {
- DirectoryInfo directory;
- public DirectoryTreeViewItem(DirectoryInfo directory)
- {
- this.directory = directory;
- ChildItems = new[] { new EmptyTreeViewItem() };
- }
- public override DirectoryInfo Directory
- {
- get { return directory; }
- }
- protected override void OnExpand()
- {
- ChildItems = directory.EnumerateDirectories().Select(item => new DirectoryTreeViewItem(item)).ToArray();
- }
- }
- public class EmptyTreeViewItem : FileSystemTreeViewItem
- {
- public override DirectoryInfo Directory
- {
- get { return null; }
- }
- protected override void OnExpand() { }
- }
- }
Und ein passendes ViewModel hab ich auch schon:
C-Quellcode
- public class MainViewModel : INotifyPropertyChanged
- {
- static MainViewModel instance;
- FileSystemTreeViewItem[] treeViewItems;
- public static MainViewModel Instance
- {
- get
- {
- return instance ?? (instance = new MainViewModel());
- }
- }
- private MainViewModel()
- {
- TreeViewItems = DriveTreeViewItem.GetDrives();
- }
- public FileSystemTreeViewItem[] TreeViewItems
- {
- get
- {
- return treeViewItems;
- }
- private set
- {
- treeViewItems = value;
- if (PropertyChanged != null)
- PropertyChanged(this, new PropertyChangedEventArgs("TreeViewItems"));
- }
- }
- public event PropertyChangedEventHandler PropertyChanged;
- }
Mein Problem ist jetzt der XAML-Code. Alles, was ich bis jetzt geschafft habe, ist das hier:
XML-Quellcode
- <Window x:Class="SimpleExplorer.MainWindow"
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:local="clr-namespace:SimpleExplorer"
- Title="MainWindow" Height="350" Width="525"
- DataContext="{x:Static local:MainViewModel.Instance}">
- <Window.Resources>
- <HierarchicalDataTemplate x:Key="ExplorerTreeViewTemplate" DataType="{x:Type local:FileSystemTreeViewItem}" ItemsSource="{Binding ChildItems}">
- <StackPanel>
- <TextBlock Text="{Binding Directory.Name}"/>
- </StackPanel>
- </HierarchicalDataTemplate>
- </Window.Resources>
- <Grid>
- <Grid.ColumnDefinitions>
- <ColumnDefinition Width="*"/>
- <ColumnDefinition Width="*"/>
- </Grid.ColumnDefinitions>
- <TreeView Grid.Column="0" ItemTemplate="{StaticResource ExplorerTreeViewTemplate}" ItemsSource="{Binding TreeViewItems}">
- </TreeView>
- <ListView Grid.Column="1">
- </ListView>
- </Grid>
- </Window>
So werden mir schonmal die Laufwerke angezeigt, auch mit dem Dummyknoten darin. Allerdings habe ich Probleme, darauf zu reagieren, wenn ein Knoten erweitert wurde. Ich möchte die Expanded-Eigenschaft jedes TreeViewItems an die Expanded-Eigenschaft des zugehörigen FileSystemTreeViewItem-Objekts binden, ich weiß aber nicht wie.
Hat da jemand ne Idee? Kann doch eigentlich nicht so schwer sein.