No.8948 實現Windows 7樣式Aero TreeView控制項(二):實現整行選中

來源:互聯網
上載者:User

記得原來做Winfrom通過Item的Bounds可以獲得整行的地區,但是在WPF中進行了幾個布局方式都沒能成功!
VS中的解決方案效果布局如下:

這樣在第一行第二列方式Border控制項,此為選中地區。而如果要實現右側系統的效果,必須要在選中地區的時候補齊第二行第一列的寬度,但是如果在TreeViewItem的Template不設定子節點列表縮排的話,將無法定位子節點列表縮排!
對比了Winform的TreeNode類型有兩個關鍵的屬性:FullPath和Level。只要知道一個就可以根據Indent算出相應的縮排寬度,從這樣的思路上,這個Item布局結構就要更改如下了:
 
代碼結構如下:

<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樣式的效果細節,後面放出。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.