[转载][WPF]TreeViewItem实现整行选中
2012-02-23 11:29
465 查看
![](http://images.cnblogs.com/cnblogs_com/o2ds/WindowsLiveWriter/No.8948Windows7AeroTreeView_D7AB/full%20selector_thumb.png)
记得原来做Winfrom通过Item的Bounds可以获得整行的区域,但是在WPF中进行了几个布局方式都没能成功!
VS中的解决方案效果布局如下:
![](http://images.cnblogs.com/cnblogs_com/o2ds/WindowsLiveWriter/No.8948Windows7AeroTreeView_D7AB/wpfTreeStyle_thumb.png)
这样在第一行第二列方式Border控件,此为选中区域。而如果要实现右侧系统的效果,必须要在选中区域的时候补齐第二行第一列的宽度,但是如果在TreeViewItem的Template不设置子节点列表缩进的话,将无法定位子节点列表缩进!
对比了Winform的TreeNode类型有两个关键的属性:FullPath和Level。只要知道一个就可以根据Indent算出相应的缩进宽度,从这样的思路上,这个Item布局结构就要更改如下了:
![](http://images.cnblogs.com/cnblogs_com/o2ds/WindowsLiveWriter/No.8948Windows7AeroTreeView_D7AB/aeroTreeStyle_thumb_1.png)
代码结构如下:
<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 indentConverter},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>
Windows 7 Aero TreeView的效果样式,不说废话,分析样式:
![](http://images.cnblogs.com/cnblogs_com/o2ds/WindowsLiveWriter/No_3E1/1_thumb.png)
![](http://images.cnblogs.com/cnblogs_com/o2ds/WindowsLiveWriter/No_3E1/image_thumb.png)
左图为Windows 7 资源管理器树型目录一部分的截图,当他放大到800%时就能看到右侧的清晰的像素级图片,可以看到音乐项的效果,放大的部分是鼠标划过树目录项的效果,简单的来分析一下效果,最外边是一个深色的单像素边框,在内侧仔细看有一层接近白色的一像素内边框,内部背景呢,则是由上而下的一个渐变颜色,用取色软件分析之后有了以下的色彩结构:
![](http://images.cnblogs.com/cnblogs_com/o2ds/WindowsLiveWriter/No_3E1/3_thumb.png)
开始的时候,我以为内边框只是一个简单单色边框,后来对比效果才发现,内边框原来也是由上而下的渐变颜色,TreeViewItem的控件模板结构如下:
<ControlTemplate TargetType="{x:Type TreeViewItem}"> <ControlTemplate.Resources> <o2ds:IndentConverter Indent="19" x:Key="indentConverter" /> </ControlTemplate.Resources> <StackPanel Height="Auto"> <Border x:Name="outBorder" BorderThickness="1" CornerRadius="2" Margin="1,1,0,0"> <Border x:Name="itemBorder" Padding="{TemplateBinding Padding}" Margin="0" CornerRadius="1" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" > <Grid Margin="{Binding Converter={StaticResource indentConverter},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> </Border> <ItemsPresenter x:Name="ItemsHost" /> </StackPanel> </ControlTemplate>
在模板里面设置了根节点StackPanel,上面分析了边框是两层,所以定义了两个嵌套的Border对象,由于某些列表项可能会有不相同的设置,所以我酌情绑定了一些相对的属性,比如说在内边框绑定Padding属性,如果真有需求比如像Margin的属性可能就要酌情绑定到外侧outBorder对象上去了,至于选中效果的布局问题我在上一篇博文里面有详细的说明,具体色彩的实现以及交互效果呢,都是通过Trigger来实现的,代码如下:
<ControlTemplate.Triggers> <Trigger Property="IsExpanded" Value="False"> <Setter TargetName="ItemsHost" Property="Visibility" Value="Collapsed" /> </Trigger> <Trigger Property="HasItems" Value="False"> <Setter TargetName="ArrowButton" Property="Visibility" Value="Hidden" /> </Trigger> <MultiTrigger> <MultiTrigger.Conditions> <Condition Property="HasHeader" Value="False" /> <Condition Property="Width" Value="Auto" /> </MultiTrigger.Conditions> <Setter TargetName="PART_Header" Property="MinWidth" Value="75" /> </MultiTrigger> <MultiTrigger> <MultiTrigger.Conditions> <Condition Property="HasHeader" Value="False" /> <Condition Property="Height" Value="Auto" /> </MultiTrigger.Conditions> <Setter TargetName="PART_Header" Property="MinHeight" Value="19" /> </MultiTrigger> <Trigger Property="IsSelected" Value="true"> <Setter TargetName="itemBorder" Property="Background" Value="{StaticResource ResourceKey=SelectedBackgroundBrush}"/> <Setter TargetName="itemBorder" Property="BorderBrush" Value="{StaticResource ResourceKey=SelectedInnerBorderBrush}" /> <Setter TargetName="outBorder" Property="BorderBrush" Value="{StaticResource ResourceKey=SelectedOutBorderBrush}" /> </Trigger> <MultiTrigger> <MultiTrigger.Conditions> <Condition Property="IsSelected" Value="true"/> <Condition Property="IsSelectionActive" Value="false"/> </MultiTrigger.Conditions> <Setter TargetName="itemBorder" Property="Background" Value="{StaticResource ResourceKey=SelectedLostFoucsBackgroundBrush}" /> <Setter TargetName="itemBorder" Property="BorderBrush" Value="{StaticResource ResourceKey=SelectedLostFoucsInnerBorderBrush}" /> <Setter TargetName="outBorder" Property="BorderBrush" Value="{StaticResource ResourceKey=SelectedLostFoucsOutBorderBrush}" /> </MultiTrigger> <MultiTrigger> <MultiTrigger.Conditions> <Condition Property="IsMouseOver" Value="True" /> <Condition Property="IsSelected" Value="True" /> </MultiTrigger.Conditions> <Setter TargetName="itemBorder" Property="Background" Value="{StaticResource ResourceKey=SelectedMouseMoveBackgroundBrush}" /> <Setter TargetName="itemBorder" Property="BorderBrush" Value="{StaticResource ResourceKey=SelectedMouseMoveInnerBorderBrush}" /> <Setter TargetName="outBorder" Property="BorderBrush" Value="{StaticResource ResourceKey=SelectedMouseMoveOutBorderBrush}" /> </MultiTrigger> <MultiTrigger> <MultiTrigger.Conditions> <Condition SourceName="itemBorder" Property="IsMouseOver" Value="True" /> <Condition Property="IsSelected" Value="False" /> </MultiTrigger.Conditions> <Setter TargetName="itemBorder" Property="Background" Value="{StaticResource ResourceKey=MouseMoveBackgroundBrush}" /> <Setter TargetName="itemBorder" Property="BorderBrush" Value="{StaticResource ResourceKey=MouseMoveInnerBorderBrush}" /> <Setter TargetName="outBorder" Property="BorderBrush" Value="{StaticResource ResourceKey=MouseMoveOutBorderBrush}" /> </MultiTrigger> </ControlTemplate.Triggers>
上面代码可以看出来这里面定义了大概四种状态,分别是:
![](http://images.cnblogs.com/cnblogs_com/o2ds/WindowsLiveWriter/No_3E1/4_thumb.png)
笔刷代码就不重复帖出了,状态效果配色方案如上所示。
此博文由Windows Live Writer 4 编辑完成,微软在前些天发布了Windows Live Essentials
Wave 4 Beta 版本在线安装包,安装后甚是欣喜,启用了全新的Ribbon工具栏,Windows Live Mail的列表加载新添了淡入效果,而Windows Live Messanger的鼠标划入也添加了更多的动画元素,其中淡入和渐变的几个特殊效果单元与Apple新发布的iOS4操作系统的很多界面元素有重合,不知道是否最新的界面设计流行元素的前兆,待而观之。
相关文章推荐
- TreeViewItem实现整行选中 (两种用法)
- WPF 中TreeView 右键选中实现
- 【WPF】如何让TreeView实现右键选中的功能
- WPF MVVM TreeView 实现 右键选中 右键菜单
- 【WPF】如何让TreeView实现右键选中的功能
- WPF TreeView 后台C#选中指定的Item, 需要遍历
- WPF TreeView 后台C#选中指定的Item, 需要遍历
- WPF 中TreeView 右键选中实现
- WPF TreeView 后台C#选中指定的Item, 需要遍历
- WPF中TreeView控件如何获取选中的TreeViewItem对象?
- WPF中确保显示TreeView选中的Item
- 如何实现具有层次结构的 TreeView <三> (WPF/TreeView/Style/Template)
- WPF自定义treeview绑定事件SelectedItemChanged
- treeview控件(动态数据绑定+整行选择)(WPF)(一)
- Wpf TreeView 延时加载实现
- 转载:jQuery点击tr实现checkbox选中的方法
- WPF中获取TreeView以及ListView获取其本身滚动条的方法,可实现自行调节scoll滚动的位置
- 采用MVVM方式实现WPF的TreeView
- wpf treeview 之 整行选中 效果
- WPF: 在 MVVM 设计中实现对 ListViewItem 双击事件的响应