递归高亮
先来修正选择高亮的问题吧。我更愿意图片中的效果称为递归高亮。递归高亮可以看作是子节点都处于非递归高亮状态。这么想的话实现起来应该非常容易。但我希望FluentTreeView能够更灵活一些。最好通过属性来切换高亮模式。
说来就来,要往TreeViewItem上加新的属性,要由TreeViewItem导出子类。要使TreeView的直接ItemContainer使用我们自定义的子类,需要继承TreeView的子类。
|
|
|
|
重写TreeView的GetContainerForItemOverride
是常规操作,大家在自定义ItemContainer的时候肯定都做过。需要注意的是TreeViewItem也是ItemsControl,它的GetContainerForItemOverride
也需要被重写。
接下来思考如何实现递归模式和非递归模式的切换。直接让子节点也处于高亮状态不错的办法,但高亮状态依赖的触发器,需要由IsSelected
属性触发。为了界面而去修改数据,违背WPF数据驱动界面的原则。那么换一种思路,不再用分治的思路,而是直接在当前节点上全部处理掉。让父节点的高亮区域覆盖所有的子节点即可。宽度已经占满,只剩下高度了。对背景色,可以直接修改最外层面板的背景色。起指示作用的矩形,则可以修改其Grid.RowSpan
让它充满整个高度。
|
|
我们根据RecursiveHighlightMode
的值在globalHighlight
和selectorGrid
里选出作为选择高亮的控件,修改selector
的Grid.RowSpan
。Grid.RowSpan
会使布局子系统的Measure
失效。在依赖属性的元数据中声明属性变化影响Measure
阶段,就实现了动态切换高亮模式。
高亮优先级
回顾一下上一篇中模板的可视化树
当选中且鼠标悬空时,root
和selectorGrid
的触发器都生效。因为root
是selectorGrid
的父级容器,渲染时就被置于靠下的一层,这就导致了选择高亮覆盖鼠标高亮的表象。要改其实很简单,把这他们两个容器的位置互换就行了。
配色太丑
剩下的就是一些小细节问题了。按照Fluent Design的标准,所有的图标都要使用Segoe MDL2 Assets
实现,并且要根据Windows当前的主题模式和主题色动态更改颜色。
Fluent.WPF可以取得主题模式和主题色对应的画刷,但在使用它之前需要先在FluentTreeViewItem
上新增属性,方便修改。
|
|
选择高亮使用SystemAltMediumHighColorBrush
,鼠标高亮使用SystemBaseMediumLowColorBrush
,选择指示用的矩形使用SystemAccentColor
。
再把Expander用Segoe MDL2 Assets
字体重新实现,我们的FluentTreeView就完成了。
递归高亮
非递归高亮
源代码参见
https://github.com/Verrickt/Melchior-Sample/tree/master/FluentTreeView_Part5