1. 程式人生 > >WPF TreeView Win8 樣式

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 所在的深度,程式碼如下所示:

 1 public static int GetDepth(this TreeViewItem item) {
 2     int depth = 0;
 3     while ((item = item.GetAncestor<TreeViewItem>()) != null) {
 4         depth++;
 5     }
 6     return
depth; 7 } 8 public static T GetAncestor<T>(this DependencyObject source) 9 where T : DependencyObject { 10 do { 11 source = VisualTreeHelper.GetParent(source); 12 } while (source != null && !(source is T)); 13 return source as T; 14 }

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

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

圖 3 自定義的 TreeView 項模板

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

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

這裡的縮排轉換器,我定義了兩個屬性: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 樣式顯示。完整的程式碼和示例可以在這裡下載。

相關推薦

WPF TreeView Win8 樣式

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

WPF TreeView自定義視覺化樹樣式

目前專案中效果(沒上傳,需要的留言) 以下例子 最終效果: TreeView 摺疊箭頭,帶垂直方向、水平方向層級線條(如圖) 來看看怎麼一步步實現吧~ 補充一點,程式碼本地試過,現剪下的所以可能部分執行顯示與截圖不完全一樣, 但基本結構是沒有問題的,可以

【原創】WPF TreeView帶連線線樣式的優化(WinFrom風格)

一、前言   之前查詢WPF相關資料的時候,發現國外網站有一個TreeView控制元件的樣式,是WinFrom風格的,樣式如下,文章連結:https://www.codeproject.com/tips/673071/wpf-treeview-with-winforms-style-fomat 

wpf treeview 數據綁定 遞歸綁定節點

group ret item path ember str part lose tex 1.先上效果 將所有節點加入ComboBox數據源,在ComboBox中選擇時下方Treeview顯示該節點下的子節點。 1.xaml文件,將以下代碼加入界面合適位置 1   

WPF TreeView IsExpanded 繫結不上的問題

最近專案上需要通過MVVM來控制TreeView,其中需要需要控制通過搜尋來定位某個節點,正常邏輯下,首先通過需要在樹上面找到該節點,然後選中該節點,並將該節點的父節點展開,這個時候需要通過MVVM來控制,需要繫結起來,只是一直沒有binding上,程式碼如下: MVVM示例程式碼: 1 usi

QML TreeView樣式和使用時的一些小細節

TreeView目前只在 Controls 1.4中有,所以在使用的時候要先匯入。   關於TreeView的Item和Model,這個在網上搜能搜到很多,同時這個在Qt Creator的歡迎介面裡輸入TreeView,選擇第一個專案,之後進入專案說明往下拉就能看到。 &nbs

WPF TreeView 相關技巧

WPF 中的 TreeView 相關實用技巧如下 響應 TreeViewItem 的雙擊事件 這是一個較怪異的問題,如果在 TreeView 的 MouseDoubleClick 中去處理 SelectedItem 時,則在當一個樹節點下只有一個子節點時,雙擊該子節點會轉到它的父節點上。 使用方法應當是

WPF TabIndex預設樣式修改:去掉預設虛線框、自定義樣式(Button控制元件為例)

去掉Tab選中預設虛線框 Tab鍵切換時,被選控制元件自動存在虛線框,有時候為了介面美觀,這個虛線框就顯得比較麻煩。廢話不多說,下面是方法。 <Window.Resources> <Style x:Key="MeyFocusVisual" TargetType="{

WPF TreeView 中迴圈遍歷查詢要素並快速定位

/// <summary> /// 獲取當前節點下符合條件的子元素 /// </summary> /// <param name="container">當前節點</param> ///

WPF TreeView BringIntoViewBehavior

由於專案需要,需要能夠定位TreeView中的點,TreeView的節點數過多的情況下,即使找到了對應的節點並選中展示了,由於不在可視區域內,給使用者的感覺還是不好,因此設計如下的Behavior,來實現選中的TreeViewItem顯示在可見區域: 1 using System; 2 using Sy

WPF TabIndex預設樣式修改:去掉預設虛線框、自定義樣式(Button控制元件為例)

去掉Tab選中預設虛線框 Tab鍵切換時,被選控制元件自動存在虛線框,有時候為了介面美觀,這個虛線框就顯得比較麻煩。廢話不多說,下面是方法。 <Window.Resources> <Style x:Key="MeyFocusVisual" Tar

WPF基礎之樣式

 樣式基礎      樣式(Style)是組織和重用格式化選項的重要工具。不是使用重複的標記填充XAML,以便設定外邊距、內邊距、顏色以及字型等細節,而是建立一系列封裝所有這些細節的樣式,然後再需要之處通過屬性來應用樣式。 樣式是可應用於元素的屬性值集合。

WPF TreeView葉子太多時顯示很慢的解決辦法

在WPF中使用DataGrid時當資料很多時也會直接顯示但是會發現,當獲取沒有顯示的DataGridRow時會出錯,原因是因為DataGrid預設開啟的虛擬載入; 今天在使用TreeView時也遇到的很多資料,顯示時出現了很長時間的卡頓,最終發現是因為TreeView預

WPF TreeView 節點選擇與展開的繫結

<TreeView.ItemContainerStyle> <Style TargetType="{x:Type TreeViewI

wpf treeView新增右擊事件

剛開始接觸WPF,今天學習了下treeView控制元件,右擊新增事件。 看了很多網上大牛的東西,終究是搞懂了。 效果圖如下: Xmal部分: <TreeView Name="DataTreeView" Margin="1" Grid.Column="0" G

WPF TreeView如何展開到某個節點

初用WPF的TreeView控制元件,需要將樹展開到某個特定的TreeViewItem,各種方法都嘗試過,卻發現程式碼總在某些情況下出錯,然後仔細研究,才發現其中的曲折。   解決問題的思路是,得到從樹的根節點到特定節點的路線,並開啟所有父節點。但是曲折的地方

WPF TreeView自定義資料模板展開到指定層

           TreeView 全部展開還是挺方便的只需設定TreeViewItem 樣式即可全部展開,但展開到具體某一級就需要手工程式碼實現。如果TreeView 沒有自定義資料模板 節點繼承TreeViewItem 那麼樹的展開可以參考 MSDN部落格  點選開

wpf treeview滾動條居左

前臺: requestbringintoview ="treeviewitem_requestbringintoview" 後臺: private void treeviewitem_requestbringintoview(object sender,reques

WPF Treeview禁止水平滾動條自動滾動

Wpf的treeview,當item超過treeview的範圍時,當點選這個item,會把這個item移到treeview的最左邊。 不想要這個效果。 需要在treeviewitem的style里加eventsetter <TreeView> <T

wpf 設定文字樣式

使用inline屬性 後臺: public static string GetInlineText(DependencyObject obj) { return (string)obj.GetValue(InlineTextProperty); } publi