WPF TreeView Win8 樣式


WPF 的 TreeView 控件自帶的樣式如圖 1 的左邊所示,節點前的箭頭還不錯,但是選中效果實在是不給力,如果想更加華麗的話,那么很有必要把 TreeView 的樣式好好自定義一番。我最后得到的結果如圖 1 的右邊所示,是一個 Win8 風格的 TreeView。

圖 1 TreeView 樣式對比

在 WPF 中,自定義控件的外觀是一件非常簡單的事情,但對於 TreeView 來說,最大的困難則在於如何做到節點的整行選擇。這是因為 TreeView 的項模板默認是如圖 2 所示的。

圖 2 TreeView 默認的項模板

最外層是一個三列兩行的 Grid,其中第一列用於放置 Expander(節點前的箭頭),剩下的列則放置 PART_Header(標頭內容)和子節點列表。因為子節點列表前空出了 Expander 那一列,所以 TreeView 的每層自然就有了縮進,同時也導致繪制邊框時,無法令邊框填滿整行——因為不知道當前節點之前有多少層縮進。雖然也有取巧的辦法,例如在繪制邊框時,令 Margin.Left 足夠小,但這僅適用於無邊框背景,在定義 Win8 樣式時不可用。

所以需要有一種辦法來計算出當前節點所在的層次(即深度)才可以。這里提供了一個好辦法,即通過在可視化樹中沿着 TreeViewItem 的父對象向上遍歷,從而得到 TreeViewItem 所在的深度,代碼如下所示:

public static int GetDepth(this TreeViewItem item) {
	int depth = 0;
	while ((item = item.GetAncestor<TreeViewItem>()) != null) {
		depth++;
	}
	return depth;
}
public static T GetAncestor<T>(this DependencyObject source)
	where T : DependencyObject {
	do {
		source = VisualTreeHelper.GetParent(source);
	} while (source != null && !(source is T));
	return source as T;
}

這里需要使用 VisualTreeHelper.GetParent 方法來得到父對象,直接用 item.Parent 得到的會是 null。

得到了深度,接下來就將 TreeViewItem 的模板重新定義一下,如圖 3 所示。

圖 3 自定義的 TreeView 項模板

在自定義的模板中,所有節點都是使用 StackPanel 層疊排列的,所以此時是沒有層次關系的,Border 是可以整行顯示的。層次關系則是通過為 Grid 指定不同的 Margin.Left 來實現的,這就需要根據當前節點的深度,計算出需要縮進的距離。計算過程是利用 IValueConverter 來完成的:

<ControlTemplate.Resources>
	<!-- 計算節點縮進的轉換器 -->
	<cw:IndentConverter Indent="10" MarginLeft="5" x:Key="IndentConverter" />
</ControlTemplate.Resources>
<Grid Margin="{Binding Converter={StaticResource IndentConverter}, RelativeSource={RelativeSource TemplatedParent}}" />
public sealed class IndentConverter : IValueConverter {
	public double Indent { get; set; }
	public double MarginLeft { get; set; }
	public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
		TreeViewItem item = value as TreeViewItem;
		if (item == null) {
			return new Thickness(0);
		}
		return new Thickness(this.MarginLeft + this.Indent * item.GetDepth(), 0, 0, 0);
	}
}

這里的縮進轉換器,我定義了兩個屬性:Indent 和 MarginLeft,這是因為我將縮進距離由 19 調整到了 12,這樣會使樹更好看點,但會導致根節點距離左邊框過近,所以就加入了 MarginLeft,使得根節點離左邊框更遠些,如圖 4 所示。

圖 4 縮進距離對比

最后,就是樣式的調整了。Win8 中的資源管理器樹狀列表的樣式如圖 5 所示,這個樣式與 Win7 差不多,但是沒有了漸變和圓角,實現起來要容易一些。需要注意的是被選中的節點,在鼠標經過的時候是會改變顏色的(雖然不是很明顯),而且箭頭無論是展開還是收起狀態,在鼠標經過的時候都會變成藍色。樣式的定義沒有什么好說的,一些顏色也在下圖中標注出來了。

圖 5 Win8 中的資源管理器

Win8 資源管理器樹狀列表最華麗的一點是,當控件沒有焦點且鼠標未經過的時候,所有箭頭是隱藏的,有焦點的時候才出現,可惜這個不知道該怎么實現,只好先放下了。

所有的樣式定義我都放在了 \Resources\Win8Theme\TreeView.xaml 文件中,這是一個資源字典,只要在需要的地方使用 <ResourceDictionary Source="Resources/Win8Theme/TreeView.xaml" /> 導入資源字典,TreeView 控件就可以以 Win8 樣式顯示。完整的代碼和示例可以在這里下載。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM