具有 HierarchicalDataTemplate 和包含子项的 ObservableCollection 的 WPF TreeView
WPF TreeView with HierarchicalDataTemplate and ObservableCollection containing Children
我正在尝试让它工作,但不幸的是我不知道我做错了什么!到目前为止,我已经调查了所有包含 TreeView 和 HierarchicalDataTemplate 的问题。
问题是:我有一个 TreeView,想显示其中包含所有子文件夹和文件的文件夹结构。为此,我创建了一个包含必要项目的 class:
public class FolderItem : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public FolderItem()
{
Files = new ObservableCollection<FileItem>();
SubFolders = new ObservableCollection<FolderItem>();
}
#region:PrivateVariables
private DirectoryInfo _Info;
private ObservableCollection<FileItem> _Files;
private ObservableCollection<FolderItem> _SubFolders;
#endregion
public DirectoryInfo Info
{
get { return _Info; }
set
{
_Info = value;
OnPropertyChanged("Info");
}
}
public ObservableCollection<FileItem> Files
{
get { return _Files; }
set
{
_Files = value;
OnPropertyChanged("Files");
}
}
public ObservableCollection<FolderItem> SubFolders
{
get { return _SubFolders; }
set
{
_SubFolders = value;
OnPropertyChanged("SubFolders");
}
}
}
public class FileItem : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
#region:PrivateVariables
private FileInfo _Info;
#endregion
public FileInfo Info
{
get { return _Info; }
set
{
_Info = value;
OnPropertyChanged("Info");
}
}
}
在代码中,我现在循环遍历所有文件夹和文件,ObservableCollection 文件夹现在显示正确的数据!我使用的代码如下所示:
public void StartExtraction(string sPath)
{
if (Directory.Exists(sPath))
{
FolderItem newFolder = new FolderItem();
newFolder.Info = new DirectoryInfo(sPath);
GetFileCount(sPath, newFolder);
Application.Current.Dispatcher.Invoke((Action)delegate ()
{
ViewModel_ZVLB.folders.Add(newFolder);
});
}
}
public void GetFileCount(string sPath, FolderItem actualFolder)
{
if (Directory.Exists(sPath))
{
foreach (string fileName in Directory.GetFiles(sPath))
{
FileItem newFile = new FileItem();
newFile.Info = new FileInfo(fileName);
actualFolder.Files.Add(newFile);
}
foreach (string subFolder in Directory.GetDirectories(sPath))
{
FolderItem newSubFolder = new FolderItem();
newSubFolder.Info = new DirectoryInfo(subFolder);
actualFolder.SubFolders.Add(newSubFolder);
GetFileCount(subFolder, newSubFolder);
}
}
}
有了这个 OC,我去了 XAML 并尝试了很多来显示数据:
<TreeView ItemsSource="{Binding folders}">
<TreeView.Resources>
<HierarchicalDataTemplate ItemsSource="{Binding folders}" DataType="{x:Type local:FolderItem}">
<HierarchicalDataTemplate.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Info.Name}" />
</DataTemplate>
</HierarchicalDataTemplate.ItemTemplate>
</HierarchicalDataTemplate>
</TreeView.Resources>
<TreeView.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
</Style>
</TreeView.ItemContainerStyle>
<TreeView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Info.FullName}" FontSize="16" FontWeight="Bold" />
</DataTemplate>
</TreeView.ItemTemplate>
</TreeView>
即使使用另一个 HierarchicalDataTemplate 也无法正常工作。
我做错了什么吗?或者它只是不适用于 ObservableCollections?
有趣的是,在 Visual Studio 2017 年更新后出现了一个新错误:As "folders" for Tpye "ViewModel_ZVLB" a instancemenber is expected! (译自德语)
这与我的问题有关吗?
感谢您的帮助!
在我看来,如果您想使用 Treeviews,为 children 使用一个 Observablecollection 会更容易。
首先,我为树的每个元素创建一个通用 class。文件夹和文件 classes 继承自它。
public class TreeItem: INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
public class FolderItem:TreeItem
{
public FolderItem()
{
Elems = new ObservableCollection<TreeItem>();
}
#region:PrivateVariables
private DirectoryInfo _Info;
private ObservableCollection<TreeItem> _Elems;
#endregion
public DirectoryInfo Info
{
get { return _Info; }
set
{
_Info = value;
OnPropertyChanged("Info");
}
}
public ObservableCollection<TreeItem> Elems
{
get { return _Elems; }
set
{
_Elems = value;
OnPropertyChanged("Elems");
}
}
}
public class FileItem : TreeItem
{
#region:PrivateVariables
private FileInfo _Info;
#endregion
public FileInfo Info
{
get { return _Info; }
set
{
_Info = value;
OnPropertyChanged("Info");
}
}
}
这里是 XAML 代码:
<TreeView ItemsSource="{Binding folders}">
<TreeView.Resources>
<HierarchicalDataTemplate ItemsSource="{Binding Elems}" DataType="{x:Type local:FolderItem}">
<TextBlock Text="{Binding Info.Name}" FontWeight="Bold"/>
</HierarchicalDataTemplate>
<DataTemplate DataType="{x:Type local:FileItem}">
<TextBlock Text="{Binding Info.Name}" />
</DataTemplate>
</TreeView.Resources>
</TreeView>
当然你需要更新你的填充函数:
public void GetFileCount(string sPath, FolderItem actualFolder)
{
if (Directory.Exists(sPath))
{
foreach (string fileName in Directory.GetFiles(sPath))
{
FileItem newFile = new FileItem();
newFile.Info = new FileInfo(fileName);
actualFolder.Elems.Add(newFile);
}
foreach (string subFolder in Directory.GetDirectories(sPath))
{
FolderItem newSubFolder = new FolderItem();
newSubFolder.Info = new DirectoryInfo(subFolder);
actualFolder.Elems.Add(newSubFolder);
GetFileCount(subFolder, newSubFolder);
}
}
}
我正在尝试让它工作,但不幸的是我不知道我做错了什么!到目前为止,我已经调查了所有包含 TreeView 和 HierarchicalDataTemplate 的问题。
问题是:我有一个 TreeView,想显示其中包含所有子文件夹和文件的文件夹结构。为此,我创建了一个包含必要项目的 class:
public class FolderItem : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public FolderItem()
{
Files = new ObservableCollection<FileItem>();
SubFolders = new ObservableCollection<FolderItem>();
}
#region:PrivateVariables
private DirectoryInfo _Info;
private ObservableCollection<FileItem> _Files;
private ObservableCollection<FolderItem> _SubFolders;
#endregion
public DirectoryInfo Info
{
get { return _Info; }
set
{
_Info = value;
OnPropertyChanged("Info");
}
}
public ObservableCollection<FileItem> Files
{
get { return _Files; }
set
{
_Files = value;
OnPropertyChanged("Files");
}
}
public ObservableCollection<FolderItem> SubFolders
{
get { return _SubFolders; }
set
{
_SubFolders = value;
OnPropertyChanged("SubFolders");
}
}
}
public class FileItem : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
#region:PrivateVariables
private FileInfo _Info;
#endregion
public FileInfo Info
{
get { return _Info; }
set
{
_Info = value;
OnPropertyChanged("Info");
}
}
}
在代码中,我现在循环遍历所有文件夹和文件,ObservableCollection 文件夹现在显示正确的数据!我使用的代码如下所示:
public void StartExtraction(string sPath)
{
if (Directory.Exists(sPath))
{
FolderItem newFolder = new FolderItem();
newFolder.Info = new DirectoryInfo(sPath);
GetFileCount(sPath, newFolder);
Application.Current.Dispatcher.Invoke((Action)delegate ()
{
ViewModel_ZVLB.folders.Add(newFolder);
});
}
}
public void GetFileCount(string sPath, FolderItem actualFolder)
{
if (Directory.Exists(sPath))
{
foreach (string fileName in Directory.GetFiles(sPath))
{
FileItem newFile = new FileItem();
newFile.Info = new FileInfo(fileName);
actualFolder.Files.Add(newFile);
}
foreach (string subFolder in Directory.GetDirectories(sPath))
{
FolderItem newSubFolder = new FolderItem();
newSubFolder.Info = new DirectoryInfo(subFolder);
actualFolder.SubFolders.Add(newSubFolder);
GetFileCount(subFolder, newSubFolder);
}
}
}
有了这个 OC,我去了 XAML 并尝试了很多来显示数据:
<TreeView ItemsSource="{Binding folders}">
<TreeView.Resources>
<HierarchicalDataTemplate ItemsSource="{Binding folders}" DataType="{x:Type local:FolderItem}">
<HierarchicalDataTemplate.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Info.Name}" />
</DataTemplate>
</HierarchicalDataTemplate.ItemTemplate>
</HierarchicalDataTemplate>
</TreeView.Resources>
<TreeView.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
</Style>
</TreeView.ItemContainerStyle>
<TreeView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Info.FullName}" FontSize="16" FontWeight="Bold" />
</DataTemplate>
</TreeView.ItemTemplate>
</TreeView>
即使使用另一个 HierarchicalDataTemplate 也无法正常工作。
我做错了什么吗?或者它只是不适用于 ObservableCollections?
有趣的是,在 Visual Studio 2017 年更新后出现了一个新错误:As "folders" for Tpye "ViewModel_ZVLB" a instancemenber is expected! (译自德语) 这与我的问题有关吗?
感谢您的帮助!
在我看来,如果您想使用 Treeviews,为 children 使用一个 Observablecollection 会更容易。
首先,我为树的每个元素创建一个通用 class。文件夹和文件 classes 继承自它。
public class TreeItem: INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
public class FolderItem:TreeItem
{
public FolderItem()
{
Elems = new ObservableCollection<TreeItem>();
}
#region:PrivateVariables
private DirectoryInfo _Info;
private ObservableCollection<TreeItem> _Elems;
#endregion
public DirectoryInfo Info
{
get { return _Info; }
set
{
_Info = value;
OnPropertyChanged("Info");
}
}
public ObservableCollection<TreeItem> Elems
{
get { return _Elems; }
set
{
_Elems = value;
OnPropertyChanged("Elems");
}
}
}
public class FileItem : TreeItem
{
#region:PrivateVariables
private FileInfo _Info;
#endregion
public FileInfo Info
{
get { return _Info; }
set
{
_Info = value;
OnPropertyChanged("Info");
}
}
}
这里是 XAML 代码:
<TreeView ItemsSource="{Binding folders}">
<TreeView.Resources>
<HierarchicalDataTemplate ItemsSource="{Binding Elems}" DataType="{x:Type local:FolderItem}">
<TextBlock Text="{Binding Info.Name}" FontWeight="Bold"/>
</HierarchicalDataTemplate>
<DataTemplate DataType="{x:Type local:FileItem}">
<TextBlock Text="{Binding Info.Name}" />
</DataTemplate>
</TreeView.Resources>
</TreeView>
当然你需要更新你的填充函数:
public void GetFileCount(string sPath, FolderItem actualFolder)
{
if (Directory.Exists(sPath))
{
foreach (string fileName in Directory.GetFiles(sPath))
{
FileItem newFile = new FileItem();
newFile.Info = new FileInfo(fileName);
actualFolder.Elems.Add(newFile);
}
foreach (string subFolder in Directory.GetDirectories(sPath))
{
FolderItem newSubFolder = new FolderItem();
newSubFolder.Info = new DirectoryInfo(subFolder);
actualFolder.Elems.Add(newSubFolder);
GetFileCount(subFolder, newSubFolder);
}
}
}