WPF TreeView sub-items 未显示
WPF TreeView sub-items not displaying
我正在尝试通过在代码中创建和添加我的 TreeViewItems
来构建 TreeView
。我有一个 Folders
的 object,其中包含 sub-folders 的列表和 Sessions
的列表。所有这些都保存在 Root
文件夹 object 中。当我使用递归创建 TreeViewItems
并将它们添加到我的 TreeView
时,根文件夹中的 Folders
和 Sessions
出现但 none显示属于他们 collection 的 24=]。
当我手写页面的 xaml 时,它会按需要显示,但在添加代码时不会显示。我查看了调试器中的 TreeView
object,我可以在 Items
collection 中看到 TreeViewItems
的第二层和第三层,但是 none 显示。
我的object
[Serializable]
public class Session
{
public int Id { get; set; }
public string Name { get; set; }
public string Address { get; set; }
public Protocol ConnectionProtocol { get; set; }
public int Port { get; set; }
}
[Serializable]
public class Folder
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
public virtual int ParentID { get; set; }
public virtual List<Folder> SubFolders { get; set; } = new List<Folder>();
public virtual List<Session> Sessions { get; set; } = new List<Session>();
}
[Serializable]
public class Root : Folder
{
public KeyValuePair<ulong, int> Version
{
get
{
return new KeyValuePair<ulong, int>(_revisionNumber, GetHashCode());
}
}
private ulong _revisionNumber = 0;
public override int Id { get => 0; set { } }
public override int ParentID { get => 0; set { } }
private void UpdateVersion()...
public bool AddSession(Session session)...
public bool RemoveSession(Session session)...
public bool AddFolder(Folder folder)...
public bool RemoveFolder(Folder folder)...
}
并且在主窗口中
private static Root root { get; set; }
private void RefreshTree()
{
SessionsTree.Items.Clear();
foreach (var sub in root.SubFolders)
SessionsTree.Items.Add(GetNodesFromFolder(sub));
foreach (var session in root.Sessions)
SessionsTree.Items.Add(BuildTreeViewItem(session));
SessionsTree.UpdateLayout();
}
private TreeViewItem GetNodesFromFolder(Folder folder)
{
TreeViewItem viewItem = BuildTreeViewItem(folder);
foreach (var sub in folder.SubFolders)
viewItem.Items.Add(GetNodesFromFolder(sub));
foreach (var session in folder.Sessions)
viewItem.Items.Add(BuildTreeViewItem(session));
return viewItem;
}
private TreeViewItem BuildTreeViewItem(Folder folder)
{
TreeViewItem viewItem = new TreeViewItem();
viewItem.Tag = folder;
viewItem.Height = 14;
Image image = new Image();
image.Source = FolderImage;
image.Height = 14;
TextBlock textBlock = new TextBlock();
textBlock.Text = folder.Name;
StackPanel stackPanel = new StackPanel();
stackPanel.Orientation = Orientation.Horizontal;
stackPanel.Children.Add(image);
stackPanel.Children.Add(textBlock);
viewItem.Header = stackPanel;
return viewItem;
}
private object BuildTreeViewItem(Session session)
{
TreeViewItem viewItem = new TreeViewItem();
viewItem.Tag = session;
Image image = new Image();
image.Source = SwitchBlue;
image.Height = 14;
TextBlock textBlock = new TextBlock();
textBlock.Text = session.Name;
textBlock.Margin = new Thickness(4, 0, 0, 0);
StackPanel stackPanel = new StackPanel();
stackPanel.Orientation = Orientation.Horizontal;
stackPanel.Children.Add(image);
stackPanel.Children.Add(textBlock);
viewItem.Header = stackPanel;
return viewItem;
}
我希望一棵树显示为...
v {} Folder 1
v {} SubFolder 1
[] Session
[] Session
> {} SubFolder 2
[] Session
> {} SubFolder 3
> {} Folder 2
> {} Folder 3
[] Session
[] Session
[] Session
但我得到的是
v {} Folder 1
v {} Folder 2
v {} Folder 3
[] Session
[] Session
[] Session
当项不包含至少一个子项时,TreeView
或实际节点将不可展开。如果您需要稍后将子项目添加到树中(例如延迟加载),您需要添加一个虚拟项目以使 TreeView
显示扩展器。由于您使用 List
作为子集合,因此您必须首先创建完整的树数据结构并将其立即添加到 TreeView.ItemSource
或简单地使用 ObservableCollection
.
为了简单起见,所有节点类型都应存储在一个共享集合中,该集合需要一个公共基类型。然后你可以简单地使用一个 DataTemplateSelector
来动态创建相应的 TreeViewItem
.
MainWindow.xaml
<Window>
<Window.DataContext>
<ViewModel />
</Window.DataContext>
<TreeView ItemsSource="{Binding Folders}"
ItemTemplateSelector="{DynamicResource DataTemplateSelector}">
<TreeView.Resources>
<local:DataTemplateSelector x:Key="DataTemplateSelector" />
<HierarchicalDataTemplate x:Key="FolderDataTemplate"
DataType="Folder"
ItemsSource="{Binding ChildItems}">
<TextBlock Text="{Binding Name}" />
</HierarchicalDataTemplate>
<DataTemplate x:Key="SessionDataTemplate"
DataType="Session">
<TextBlock Text="{Binding Name}" />
</DataTemplate>
</TreeView.Resources>
</TreeView>
</Window>
DataTemplateSelector.cs
class DataTemplateSelector : System.Windows.Controls.DataTemplateSelector
{
public override DataTemplate
SelectTemplate(object item, DependencyObject container)
{
FrameworkElement element = container as FrameworkElement;
return item is Session
? element.FindResource("SessionDataTemplate") as DataTemplate
: element.FindResource("FolderDataTemplate") as DataTemplate;
}
}
ViewModel.cs
class ViewModel
{
public ObservableCollection<Folder> Folders { get; set; }
public ViewModel()
{
this.Folders = new ObservableCollection<Folder>
{
new Folder("Folder_1")
{
ChildItems = new ObservableCollection<TreeItem>
{
new Folder("Folder_1.1")
{
ChildItems = new ObservableCollection<TreeItem>
{
new Folder("Folder_1.1.1")
{
ChildItems = new ObservableCollection<TreeItem>
{
new Session("SessionA"),
new Session("SeesionB")
}
},
new Session("SessionA"),
new Session("SeesionB")
}
},
new Folder("Folder_1.2")
{
ChildItems = new ObservableCollection<TreeItem>
{
new Session("SessionA"),
new Session("SeesionB")
}
}
}
}
};
}
}
数据项层次结构
public abstract class TreeItem
{
public TreeItem(String name)
{
this.Name = name;
}
public string Name { get; set; }
}
public class Folder : TreeItem
{
public Folder(string name) : base(name)
{
}
public ObservableCollection<TreeItem> ChildItems { get; set; } = new ObservableCollection<TreeItem>();
}
public class Session : TreeItem
{
public Session(string name) : base(name)
{
}
}
我正在尝试通过在代码中创建和添加我的 TreeViewItems
来构建 TreeView
。我有一个 Folders
的 object,其中包含 sub-folders 的列表和 Sessions
的列表。所有这些都保存在 Root
文件夹 object 中。当我使用递归创建 TreeViewItems
并将它们添加到我的 TreeView
时,根文件夹中的 Folders
和 Sessions
出现但 none显示属于他们 collection 的 24=]。
当我手写页面的 xaml 时,它会按需要显示,但在添加代码时不会显示。我查看了调试器中的 TreeView
object,我可以在 Items
collection 中看到 TreeViewItems
的第二层和第三层,但是 none 显示。
我的object
[Serializable]
public class Session
{
public int Id { get; set; }
public string Name { get; set; }
public string Address { get; set; }
public Protocol ConnectionProtocol { get; set; }
public int Port { get; set; }
}
[Serializable]
public class Folder
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
public virtual int ParentID { get; set; }
public virtual List<Folder> SubFolders { get; set; } = new List<Folder>();
public virtual List<Session> Sessions { get; set; } = new List<Session>();
}
[Serializable]
public class Root : Folder
{
public KeyValuePair<ulong, int> Version
{
get
{
return new KeyValuePair<ulong, int>(_revisionNumber, GetHashCode());
}
}
private ulong _revisionNumber = 0;
public override int Id { get => 0; set { } }
public override int ParentID { get => 0; set { } }
private void UpdateVersion()...
public bool AddSession(Session session)...
public bool RemoveSession(Session session)...
public bool AddFolder(Folder folder)...
public bool RemoveFolder(Folder folder)...
}
并且在主窗口中
private static Root root { get; set; }
private void RefreshTree()
{
SessionsTree.Items.Clear();
foreach (var sub in root.SubFolders)
SessionsTree.Items.Add(GetNodesFromFolder(sub));
foreach (var session in root.Sessions)
SessionsTree.Items.Add(BuildTreeViewItem(session));
SessionsTree.UpdateLayout();
}
private TreeViewItem GetNodesFromFolder(Folder folder)
{
TreeViewItem viewItem = BuildTreeViewItem(folder);
foreach (var sub in folder.SubFolders)
viewItem.Items.Add(GetNodesFromFolder(sub));
foreach (var session in folder.Sessions)
viewItem.Items.Add(BuildTreeViewItem(session));
return viewItem;
}
private TreeViewItem BuildTreeViewItem(Folder folder)
{
TreeViewItem viewItem = new TreeViewItem();
viewItem.Tag = folder;
viewItem.Height = 14;
Image image = new Image();
image.Source = FolderImage;
image.Height = 14;
TextBlock textBlock = new TextBlock();
textBlock.Text = folder.Name;
StackPanel stackPanel = new StackPanel();
stackPanel.Orientation = Orientation.Horizontal;
stackPanel.Children.Add(image);
stackPanel.Children.Add(textBlock);
viewItem.Header = stackPanel;
return viewItem;
}
private object BuildTreeViewItem(Session session)
{
TreeViewItem viewItem = new TreeViewItem();
viewItem.Tag = session;
Image image = new Image();
image.Source = SwitchBlue;
image.Height = 14;
TextBlock textBlock = new TextBlock();
textBlock.Text = session.Name;
textBlock.Margin = new Thickness(4, 0, 0, 0);
StackPanel stackPanel = new StackPanel();
stackPanel.Orientation = Orientation.Horizontal;
stackPanel.Children.Add(image);
stackPanel.Children.Add(textBlock);
viewItem.Header = stackPanel;
return viewItem;
}
我希望一棵树显示为...
v {} Folder 1
v {} SubFolder 1
[] Session
[] Session
> {} SubFolder 2
[] Session
> {} SubFolder 3
> {} Folder 2
> {} Folder 3
[] Session
[] Session
[] Session
但我得到的是
v {} Folder 1
v {} Folder 2
v {} Folder 3
[] Session
[] Session
[] Session
当项不包含至少一个子项时,TreeView
或实际节点将不可展开。如果您需要稍后将子项目添加到树中(例如延迟加载),您需要添加一个虚拟项目以使 TreeView
显示扩展器。由于您使用 List
作为子集合,因此您必须首先创建完整的树数据结构并将其立即添加到 TreeView.ItemSource
或简单地使用 ObservableCollection
.
为了简单起见,所有节点类型都应存储在一个共享集合中,该集合需要一个公共基类型。然后你可以简单地使用一个 DataTemplateSelector
来动态创建相应的 TreeViewItem
.
MainWindow.xaml
<Window>
<Window.DataContext>
<ViewModel />
</Window.DataContext>
<TreeView ItemsSource="{Binding Folders}"
ItemTemplateSelector="{DynamicResource DataTemplateSelector}">
<TreeView.Resources>
<local:DataTemplateSelector x:Key="DataTemplateSelector" />
<HierarchicalDataTemplate x:Key="FolderDataTemplate"
DataType="Folder"
ItemsSource="{Binding ChildItems}">
<TextBlock Text="{Binding Name}" />
</HierarchicalDataTemplate>
<DataTemplate x:Key="SessionDataTemplate"
DataType="Session">
<TextBlock Text="{Binding Name}" />
</DataTemplate>
</TreeView.Resources>
</TreeView>
</Window>
DataTemplateSelector.cs
class DataTemplateSelector : System.Windows.Controls.DataTemplateSelector
{
public override DataTemplate
SelectTemplate(object item, DependencyObject container)
{
FrameworkElement element = container as FrameworkElement;
return item is Session
? element.FindResource("SessionDataTemplate") as DataTemplate
: element.FindResource("FolderDataTemplate") as DataTemplate;
}
}
ViewModel.cs
class ViewModel
{
public ObservableCollection<Folder> Folders { get; set; }
public ViewModel()
{
this.Folders = new ObservableCollection<Folder>
{
new Folder("Folder_1")
{
ChildItems = new ObservableCollection<TreeItem>
{
new Folder("Folder_1.1")
{
ChildItems = new ObservableCollection<TreeItem>
{
new Folder("Folder_1.1.1")
{
ChildItems = new ObservableCollection<TreeItem>
{
new Session("SessionA"),
new Session("SeesionB")
}
},
new Session("SessionA"),
new Session("SeesionB")
}
},
new Folder("Folder_1.2")
{
ChildItems = new ObservableCollection<TreeItem>
{
new Session("SessionA"),
new Session("SeesionB")
}
}
}
}
};
}
}
数据项层次结构
public abstract class TreeItem
{
public TreeItem(String name)
{
this.Name = name;
}
public string Name { get; set; }
}
public class Folder : TreeItem
{
public Folder(string name) : base(name)
{
}
public ObservableCollection<TreeItem> ChildItems { get; set; } = new ObservableCollection<TreeItem>();
}
public class Session : TreeItem
{
public Session(string name) : base(name)
{
}
}