• No.8948 实现Windows 7样式Aero TreeView控件(二):实现整行选中


    full selector

    记得原来做Winfrom通过Item的Bounds可以获得整行的区域,但是在WPF中进行了几个布局方式都没能成功!
    VS中的解决方案效果布局如下:

    wpfTreeStyle

    这样在第一行第二列方式Border控件,此为选中区域。而如果要实现右侧系统的效果,必须要在选中区域的时候补齐第二行第一列的宽度,但是如果在TreeViewItem的Template不设置子节点列表缩进的话,将无法定位子节点列表缩进!
    对比了Winform的TreeNode类型有两个关键的属性:FullPath和Level。只要知道一个就可以根据Indent算出相应的缩进宽度,从这样的思路上,这个Item布局结构就要更改如下了:
    aeroTreeStyle 
    代码结构如下:

    <StackPanel>

        <Border x:Name=”itemBorder”>

               <Grid>

                      <Grid.ColumnDefinitions>

                            <ColumnDefinitions Width=”19” />

                            <ColumnDefinitions Width=”*” />

                      </Grid.ColumnDefinitions>

                      <Path x:Name=”TreeArrow” Grid.Column=”0” />

                      <ContentPresenter ContentSource=”Header” Grid.Column=”1”  />

               </Grid>

       </Border>

       <ItemsPresenter x:Name="ItemsHost" />

    </StackPanel>

    可是此时的子节点列表没有缩进怎么办?
    做几个预备动作,在TreeViewItem里面有一个TreeNode的特殊特性,叫做Level,获得节点所在的层级,在这里我做了个Extensions类:

    public static class TreeViewItemExtensions
       {
           public static int GetDepth(this TreeViewItem item)
           {
               FrameworkElement elem = item;
               while (elem.Parent != null)
               {
                   var tvi = elem.Parent as TreeViewItem;
                   if (null != tvi)
                       return tvi.GetDepth() + 1;
                   elem = elem.Parent as FrameworkElement;
               }
               return 0;
           }
       }

    用来获得TreeViewItem在TreeView里面的层级深度。然后就是怎么将缩进的绑定到它该在的地方了!

    在上面那段TreeViewItem的Template代码里面的itemBorder就是节点项的整体范围了,如果我们想让选中边框始终保持Aero样式中满行选中的状态就只能在itemBorder中的Grid上做手脚了,上面扩展了TreeViewItem对象,可以获取的到层级深度,而缩进值则等于节点层级和缩进值的乘积,而应用缩进值需要实现一个缩进的转换类型方法:

    public class IndentConverter:IValueConverter
        {
            public double Indent{ get; set; }

            public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
            {
                var item = value as TreeViewItem;
                if (null == item)
                    return new Thickness(0);
                return new Thickness(Indent* item.GetDepth(), 0, 0, 0);
            }

            public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
            {
                throw new NotImplementedException();
            }
        }


    然后就是改造上一段模板内容。完整代码如下:

    <Style TargetType="{x:Type TreeViewItem}" x:Key="aaa">
           <Setter Property="FocusVisualStyle" Value="{StaticResource TreeViewItemFocusVisual}"/>
           <Setter Property="Template">
               <Setter.Value>
                   <ControlTemplate TargetType="{x:Type TreeViewItem}">
                       <ControlTemplate.Resources>
                          <o2ds:IndentConverter Indent="19" x:Key="indentConverter" />
                       </ControlTemplate.Resources>
                       <StackPanel>
                           <Border Name="itemBackground" Background="{TemplateBinding Background}"
                                    BorderBrush="{TemplateBinding BorderBrush}"
                                    BorderThickness="{TemplateBinding BorderThickness}"
                                    Padding="{TemplateBinding Padding}">
                               <Grid Margin="{Binding Converter={StaticResource lengthConverter},RelativeSource={RelativeSource TemplatedParent}}">
                                   <Grid.ColumnDefinitions>
                                       <ColumnDefinition Width="19" />
                                       <ColumnDefinition />
                                   </Grid.ColumnDefinitions>
                                   <ToggleButton Grid.Column="0" x:Name="ArrowButton" Style="{StaticResource TreeViewArrowButtonStyle}"
                                                 IsChecked="{Binding Path=IsExpanded, RelativeSource={RelativeSource TemplatedParent}}"
                                                 ClickMode="Press" />
                                   <ContentPresenter Grid.Column="1" x:Name="PART_Header" ContentSource="Header"
                                                     HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" />
                               </Grid>
                           </Border>
                           <ItemsPresenter x:Name="ItemsHost" />
                       </StackPanel>

                    <ControlTemplate.Triggers>

                      Trigger something…
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

     

     

    <Grid Margin="{Binding Converter={StaticResource indentConverter},RelativeSource={RelativeSource TemplatedParent}}">

    indentConverter对象承担了获取深度以及转换边距的任务。由此我们就完成了实现整行选中TreeViewItem的任务,至于Aero样式的效果细节,后面放出。

  • 相关阅读:
    Linux中yum命令镜像源和出错解决方案
    Redis编译安装
    Linux下安装Redis
    zabbix3.4.2的安装及配置
    【前端】活动表单
    【笔记】archlinux缺少部分常用工具
    【笔记】BootstrapTable带参数刷新数据的坑
    【笔记】Win7连接公司内网无法打开网页
    【笔记】Archlinux下配置rsyslog写日志到mysql
    【笔记】Gave up waiting for suspend/resume device
  • 原文地址:https://www.cnblogs.com/o2ds/p/1763021.html
Copyright © 2020-2023  润新知