TreeView顾名思义,就是以树形展示数据。最简单的比喻就是一个文件目录树。
UWP中的TreeView是一个XAML控件,支持以下功能:
- N级嵌套
- 支持选择一个或者多个节点
- 支持ItemsSource的数据绑定
- 以TreeViewItem为TreeView的根节点
- TreeViewItem的内容可以是任意类型
- 在TreeView之间拖放
由于可以嵌套,TreeView的节点带有Chevron图标,用于展示节点是关闭还是打开。另外,每一个节点也额外携带一个图标。
创建一个TreeView,既可以指定其ItemsSource,也可以显示往其RootNodes辖属中添加TreeViewNode。每个TreeViewNode的Children属性也可以添加子TreeViewNode。
1809 Win10 开始,TreeView的才支持ItemsSource辖属。不过你也可以直接使用WinUI中的版本。
下面是一个显示指定TreeViewNode的例子:
<muxc:TreeView>
<muxc:TreeView.RootNodes>
<muxc:TreeViewNode Content="Flavors"
IsExpanded="True">
<muxc:TreeViewNode.Children>
<muxc:TreeViewNode Content="Vanilla"/>
<muxc:TreeViewNode Content="Strawberry"/>
<muxc:TreeViewNode Content="Chocolate"/>
</muxc:TreeViewNode.Children>
</muxc:TreeViewNode>
</muxc:TreeView.RootNodes>
</muxc:TreeView>
下面的例子针对对于层级类型的数据:
<muxc:TreeView ItemsSource="{x:Bind DataSource}">
<muxc:TreeView.ItemTemplate>
<DataTemplate x:DataType="local:Item">
<muxc:TreeViewItem ItemsSource="{x:Bind Children}"
Content="{x:Bind Name}"/>
</DataTemplate>
</muxc:TreeView.ItemTemplate>
</muxc:TreeView>
如果使用TreeView.ItemsSource,下面的API或许有帮助:
- ItemFromContainer,从TreeViewItem中获取数据条目
- ContainerFromItem,从数据条目获取TreeViewItem
- NodeFromContainer, 从TreeViewItem获取TreeViewNode
- ContainerFromNode,从TreeViewNode获取TreeViewitem
每个TreeViewNode有下面的辖属:
- Children
- HasChildren
- HasUnrealizedChildren
- Depth,到RootNodes的距离
- Parent
TreeViewNode的Content支持IInspectable类型。如果Content不是String类型,那么需要指定ItemTemplate来告诉TreeView怎么显示这个Content。在1803 Win10以前,ItemTemplate不存在,如果内容不是string的话,需要定制TreeView的模板来显示内容。
在TreeView上,可以通过修改ItemContainerStyle或者ItemContainerStyleSelector来定制应用于TreeViewItem的样式。下面是例子:
<muxc:TreeView>
<muxc:TreeView.ItemContainerStyle>
<Style TargetType="muxc:TreeViewItem">
<Setter Property="CollapsedGlyph" Value=""/>
<Setter Property="ExpandedGlyph" Value=""/>
<Setter Property="GlyphBrush" Value="DarkOrange"/>
</Style>
</muxc:TreeView.ItemContainerStyle>
<muxc:TreeView.RootNodes>
<muxc:TreeViewNode Content="Flavors"
IsExpanded="True">
<muxc:TreeViewNode.Children>
<muxc:TreeViewNode Content="Vanilla"/>
<muxc:TreeViewNode Content="Strawberry"/>
<muxc:TreeViewNode Content="Chocolate"/>
</muxc:TreeViewNode.Children>
</muxc:TreeViewNode>
</muxc:TreeView.RootNodes>
</muxc:TreeView>
ItemTemplateSelector的话,则是让TreeView在应对不同的TreeViewNode采用不同的DataTemplate。例子:
<Page.Resources>
<DataTemplate x:Key="FolderTemplate" x:DataType="local:ExplorerItem">
<muxc:TreeViewItem ItemsSource="{x:Bind Children}">
<StackPanel Orientation="Horizontal">
<Image Width="20" Source="Assets/folder.png"/>
<TextBlock Text="{x:Bind Name}" />
</StackPanel>
</muxc:TreeViewItem>
</DataTemplate>
<DataTemplate x:Key="FileTemplate" x:DataType="local:ExplorerItem">
<muxc:TreeViewItem>
<StackPanel Orientation="Horizontal">
<Image Width="20" Source="Assets/file.png"/>
<TextBlock Text="{x:Bind Name}"/>
</StackPanel>
</muxc:TreeViewItem>
</DataTemplate>
<local:ExplorerItemTemplateSelector
x:Key="ExplorerItemTemplateSelector"
FolderTemplate="{StaticResource FolderTemplate}"
FileTemplate="{StaticResource FileTemplate}" />
</Page.Resources>
<Grid>
<muxc:TreeView
ItemsSource="{x:Bind DataSource}"
ItemTemplateSelector="{StaticResource ExplorerItemTemplateSelector}"/>
</Grid>
需要你自定义一个DataTemplateSelector:
public class ExplorerItemTemplateSelector : DataTemplateSelector
{
public DataTemplate FolderTemplate { get; set; }
public DataTemplate FileTemplate { get; set; }
protected override DataTemplate SelectTemplateCore(object item)
{
var explorerItem = (ExplorerItem)item;
if (explorerItem.Type == ExplorerItem.ExplorerItemType.Folder) return FolderTemplate;
return FileTemplate;
}
}
传给SelectTemplateCore的参数取决于:
- 如果使用的是ItemsSource,那么则取决于ItemsSource中条目的类型
- 如果使用的是TreeViewNode,那么传入的参数就是TreeViewNode类型,可以从TreeViewNode.Content获取数据
Interacting with a tree view
TreeView支持以下操作:
- 展开或者合并节点
- 单点或者多点选择
- 点击调用节点
具有子节点的枝干节点可以被点击展开或者合并。也可以在代码中调用TreeView的Collapse以及Expand方法来实现同样的操作,所需参数是具体的TreeViewNode。每个TreeViewNode有IsExpanded辖属,可以用来查看是否展开。
一个节点的内容可以在展开的时候加载。你需要处理Expanding事件,并判断HasUnrealizedChildren是否为真。下面是一个例子:
private void SampleTreeView_Expanding(muxc.TreeView sender, muxc.TreeViewExpandingEventArgs args)
{
if (args.Node.HasUnrealizedChildren)
{
FillTreeNode(args.Node);
}
}
你也可以选择处理Collapsed事件来移除子节点:
private void SampleTreeView_Collapsed(muxc.TreeView sender, muxc.TreeViewCollapsedEventArgs args)
{
args.Node.Children.Clear();
args.Node.HasUnrealizedChildren = true;
}
用户点击的时候可以触发某个操作,而不是去选中对应的节点。这可以通过ItemInvoked事件来实现。ListView也可以用于动作触发,但是需要开启IsItemClickEnabled辖属。
对于条目选取的话,默认是关的,需要设置TreeView.SelectionMode成Single或者Multiple。多选的情况下,每个节点前面会出现一个选择框,供选取多个用。选取的节点会被添加到TreeView的SelectedNodes合集。另外可以通过SelectAll方法来选取所有节点。确保只在多选模式下调用SelectAll。
对于unrealized的节点,在选取的时候不做考虑。其他一些额外的注意事项:
- 当用户选取了一个父节点,所有具现化的节点会被选取。同样的,子节点的选取也会导致父节点选取。
- SelectAll 只会添加具现化的节点到SelectedNodes。
- 如果一个父节点被选中,那么其子节点具现化的时候也会被选取。
下面是一些例子:
- Tree view using XAML
- Tree view using data binding
- Pictures and Music library tree view
- Drag and drop items between tree views
(完)