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

数据模板 (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>

如何实现具有层次结构的 TreeView <三> (WPF/TreeView/Style/Template)_第1张图片


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>



通过上面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),令其在不同状态下呈现出不同的颜色、边框及背景等。

你可能感兴趣的:(Path,LINQ,WPF,setter,binding,DataTemplate)