如何实现具有层次结构的 TreeView <三> (WPF/TreeView/Style/Template)

来源:互联网 发布:中国网络集成公司排名 编辑:程序博客网 时间:2024/06/06 13:20

数据模板 (DataTemplate) 和数据绑定 (Data Binding)

为了把数据和界面进行关联,我们要做 3 件事:

1、在 MainWindow.xaml 中添加一个 TreeView 控件

<TreeView x:Name="tv"></TreeView>

2、将数据绑定到 TreeView 控件上

在 WPF 中实现数据绑定的方法主要有2种: 在 XAML 中声明或在 Code 中指定。详细信息请参考 MSDN:
Windows Presentation Foundation 数据绑定 <一>
Windows Presentation Foundation 数据绑定 <二>

由于此处的 TreeView 顶层节点需要 ParentID 为 NULL 的数据,所以我采用了在 Code 中指定的方式。
/// <summary>/// MainWindow.xaml 的交互逻辑/// </summary>public partial class MainWindow : Window{    public MainWindow()    {        InitializeComponent();        // 添加 MainWindow.Loaded 事件        this.Loaded += new RoutedEventHandler(MainWindow_Loaded);    }    private void MainWindow_Loaded(object sender, RoutedEventArgs e)    {        // 在代码中为 TreeView 控件设置 ItemsSource 属性        var dc = new CSDNBlogDataContext();        var items = dc.Departments.Where(item => item.ParentID == null);        tv.ItemsSource = items.ToArray();    }}

关于 LINQ 请参考 MSDN:
LINQ 查询表达式 (C# 编程指南)
101 LINQ Samples

完成以上工作并运行程序,将看到类似下图中显示的界面:

未定义数据模板

从上面的图片可以看出,每一个 ListViewItem 都绑定了一个 Department 对象,由于我们尚未告诉 ListViewItem 如何显示 Department 对象的内容(即属性),所以系统默认分配了一个 TextBlock 控件,并将 Department.ToString() 的信息给呈现了出来。那 Department 的对象内容该如何显示呢?

3、为 TreeView 控件添加数据模板 (DataTemplate)

数据模板 (DataTemplate 类) 用于描述数据对象的可视化结构。


打个比方,当前工程中用到的数据对象是 Department,而每个 Department 都拥有4个属性: DepartmentID、ParentID、Name 和 Type。当我们将每个 Department 与 TreeViewItem 进行关联(即数据绑定)之后,我们应该告诉 TreeViewItem 如何呈现与其关联的 Department 对象,简单理解就是如何显示 Department 的那4个属性。而 DataTemplate 就是用来定义这个结构的东东。


通常,描述数据对象的可视化结构,直接使用 DataTemplate 就可以了。但是当前工程中的 Department 是可以包含“子部门”的数据项,而且其深度未知。所以,此处使用的是 HierarchicalDataTemplate 类,即允许包含“子数据项”的 DataTemplate.


例如:

a、使用一个 TextBlock 对象,仅用于呈现与该 ListViewItem 关联的 Department 对象的 Name 属性

<TreeView.ItemTemplate>    <HierarchicalDataTemplate ItemsSource="{Binding Path=Children}">        <TextBlock Text="{Binding Path=Name}"/>    </HierarchicalDataTemplate></TreeView.ItemTemplate>

仅绑定名称


b、稍微复杂一点的结构,呈现 Name(Type) 形式的2个属性。

<TreeView.ItemTemplate>    <HierarchicalDataTemplate ItemsSource="{Binding Path=Children}">        <!--<TextBlock Text="{Binding Path=Name}"/>-->        <StackPanel Orientation="Horizontal">            <TextBlock Text="{Binding Path=Name}"/>            <TextBlock Text="("/>            <TextBlock Text="{Binding Path=Type}"/>            <TextBlock Text=")"/>        </StackPanel>    </HierarchicalDataTemplate></TreeView.ItemTemplate>

绑定Name_Type


通过上面2个简单的示例,我们应该对 DataTemplate 是如何描述数据对象的可视化结构有了一个直观的了解。


接下来,将介绍如何实现文本的纵向显示,这里有个概念需要先说明下:

一个字符串 (String) 可以被看作是一个字符数组 (Char[])

根据这一特性,我们可以将一个字符串作为数据源绑定到某个支持 ItemsSource 或 IsItemsHost 属性的控件上。例如: 将 Name 属性指定给 StackPanel、Grid、ListBox 或者 ItemsControl 等对象。

同时,基于 WPF 的数据转换规则,该字符串中的每个 Char 对象都将被自动转换为 String 对象输出到用户界面。


根据上述特征,修改一下 DataTemplate 就能实现文本的纵向显示了:

<TreeView.ItemTemplate>    <HierarchicalDataTemplate ItemsSource="{Binding Path=Children}">        <!--<TextBlock Text="{Binding Path=Name}"/>-->        <!--<StackPanel Orientation="Horizontal">            <TextBlock Text="{Binding Path=Name}"/>            <TextBlock Text="("/>            <TextBlock Text="{Binding Path=Type}"/>            <TextBlock Text=")"/>        </StackPanel>-->        <ItemsControl ItemsSource="{Binding Path=Name}">            <ItemsControl.Style>                <Style TargetType="{x:Type ItemsControl}">                    <Setter Property="Template">                        <Setter.Value>                            <ControlTemplate TargetType="{x:Type ItemsControl}">                                <Grid>                                    <ItemsPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"/>                                </Grid>                            </ControlTemplate>                        </Setter.Value>                    </Setter>                </Style>            </ItemsControl.Style>            <ItemsControl.ItemTemplate>                <DataTemplate>                    <TextBlock x:Name="block" RenderTransformOrigin="0.5,0.5" Text="{Binding}" TextAlignment="Center"/>                    <DataTemplate.Triggers>                        <DataTrigger Binding="{Binding}" Value="(">                            <Setter TargetName="block" Property="RenderTransform">                                <Setter.Value>                                    <RotateTransform Angle="90"/>                                </Setter.Value>                            </Setter>                        </DataTrigger>                        <DataTrigger Binding="{Binding}" Value=")">                            <Setter TargetName="block" Property="RenderTransform">                                <Setter.Value>                                    <RotateTransform Angle="90"/>                                </Setter.Value>                            </Setter>                        </DataTrigger>                        <DataTrigger Binding="{Binding}" Value="-">                            <Setter TargetName="block" Property="RenderTransform">                                <Setter.Value>                                    <RotateTransform Angle="90"/>                                </Setter.Value>                            </Setter>                        </DataTrigger>                    </DataTemplate.Triggers>                </DataTemplate>            </ItemsControl.ItemTemplate>        </ItemsControl>    </HierarchicalDataTemplate></TreeView.ItemTemplate>

纵向显示


此时,数据绑定和数据模板定义已经完成。下一节将介绍:

1、如何布局 TreeView 控件,实现节点的横向排列 (从左到右,自上而下) 的视图。

2、为 TreeViewItem 设置控件模板 (ControlTemplate) 和触发器 (Trigger),令其在不同状态下呈现出不同的颜色、边框及背景等。

原创粉丝点击