WPF 类windows资源管理器(一)——TreeViewItem改造

与之前发布的有修改!!

之前的版本,在某些情况下会失效(在鼠标悬停在某一行的空白处时,不会改变整行的背景色)。终其原因,是因为Border的背景为透明(Transparent),或者为null时,无法检测鼠标(我猜测是这样的)。因此,要解决这个问题,就必须让Border的内容,填充整个区域。 

目标:做一个类似windows资源管理器的TreeView控件,用于展示层次化的数据结构。

功能要求:

        鼠标悬停某一项时,改变整行的背景(而不是只改变内容部分的背景)

指定TreeView控件的数据源时,它默认会以TreeViewItem来展示每一个项。因此,TreeViewItem的样式,就非常重要。

一、TreeViewItem的布局

1.1 反编译TreeViewItem控件的Template属性,得到WPF默认的模板代码:

<!-- 为了方便各位学习,此处代码已经精简了布局无关的样式、触发器代码 -->
<ControlTemplate TargetType="TreeViewItem" >
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto" MinWidth="19" />
            <ColumnDefinition Width="Auto" />
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition />
        </Grid.RowDefinitions>

        <ToggleButton IsChecked="False" ClickMode="Press" Name="Expander"/>

        <Border Name="Bd"  Grid.Column="1">

            <ContentPresenter ContentSource="Header" Name="PART_Header"                                     
                                Content="{TemplateBinding HeaderedContentControl.Header}"/>
        </Border>

        <ItemsPresenter Name="ItemsHost" Grid.Column="1" Grid.Row="1" Grid.ColumnSpan="2" />

    </Grid>

</ControlTemplate>

此处布局的样式如下图所示:

从上图可知,每一个TreeViewItem的面板,都是一个两行、三列的Grid;

1:每个TreeViewItem都有一个ToggleButton,通过它的ControlTemplate,只是它的形状是一个三角形(每一项前面的三角形符号)

2:ContentPresenter控件表示内容控件,因为TreeViewItem是HeaderContentItemControl,所以设置ContentSource="Header",表示这个内容控件显示Header属性的内容。使用Border包裹它,用来设置背景色、边框等样式

3:ItemsPresenter表示该项的子项,它放在表格的第二行、第二列。

4:如此嵌套下去,则子项永远放在父项布局容器的第二行、第二列,因此产生类似缩进的效果。

5:代码中还有一个触发器(Trigger),用于当行为、属性值变成指定的值时,按指定的方式修改样式。

二、修改TreeViewItem模板 

既然了解了TreeViewItem的默认模板构造,就可以动手自己修改模板了。要想整行选中,则必须有一个元素能填充整行,并且可以有IsMouseOver的触发器。很自然就想到了Border

如下代码所示:

<!-- 为了方便学习,精简了布局无关的代码 -->
<ControlTemplate TargetType="TreeViewItem">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition />
        </Grid.RowDefinitions>

        <!-- 不能绑定Background属性,否则IsMouseOver触发器会失效 -->
        <Border Name="Bd" SnapsToDevicePixels="True" 
            BorderThickness="{TemplateBinding Border.BorderThickness}" 
            Padding="{TemplateBinding Control.Padding}" 
            BorderBrush="{TemplateBinding Border.BorderBrush}" >

            <Border.Style>
                <Style TargetType="Border">
                    <Style.Triggers>
                        <Trigger Property="IsMouseOver" Value="True">
                            <Setter Property="Background" Value="LightBlue"/>
                        </Trigger>
                    </Style.Triggers>
                </Style>
            </Border.Style>

            <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="auto"/>
                    <ColumnDefinition Width="*"/>
                </Grid.ColumnDefinitions>

                <!-- 绑定IsChecked属性到父级元素的IsExpanded属性:否则点击ToggleButton不起作用 -->
                <ToggleButton Grid.Column="0" ClickMode="Press" Name="Expander" 
                              IsChecked="{Binding IsExpanded, RelativeSource={RelativeSource TemplatedParent}}"/ >
                    
                <!-- HorizontalAlignment必须为Stretch,才能在鼠标进入该行的空白区域时,Border的触发器也发挥作用:默认的水平对齐为左对齐,导致内容区域只有一点点,使得鼠标只有在进入内容区域时,Border的触发器才起作用-->
                <ContentPresente
  • 5
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值