WPF TreeView 虛擬化-設置滾動到選中項 WPF 列表開啓虛擬化的方式

原文: WPF TreeView 虛擬化-設置滾動到選中項

前言

列表滾動到具體的數據項?html

ListBox提供了簡易快捷的滾動定位函數ScrollIntoView。函數

TreeView樹狀結構列表,則沒有此類方法,沒法與ListBox同樣,直接設置滾動到具體的數據項。post

同時,SelectedItem也是隻讀的,沒法設置SelectedItem來間接的設置滾動項。url

TreeView滾動定位

1. 對TreeViewItem添加一個附加屬性IsScrolledToViewWhenSelected,在屬性變動事件中,添加對Loaded事件的訂閱和註銷spa

 1     static void OnIsScrolledToViewWhenSelectedChanged(
 2         DependencyObject depObj, DependencyPropertyChangedEventArgs e)
 3     {
 4         if (depObj is TreeViewItem treeViewItem && e.NewValue is bool isIntoViewWhenSelected)
 5         {
 6             treeViewItem.Loaded -= TreeViewItem_Loaded;
 7             if (isIntoViewWhenSelected)
 8             {
 9                 treeViewItem.Loaded += TreeViewItem_Loaded;
10             }
11         }
12     }

2. 在Loaded事件中,根據當前TreeViewItem是否選中,調用是否滾動到視圖區域的邏輯code

 1     static void TreeViewItem_Loaded(object sender, RoutedEventArgs e)
 2     {
 3         var treeViewItem = e.OriginalSource as TreeViewItem;
 4         if (treeViewItem != null)
 5         {
 6             treeViewItem.Loaded -= TreeViewItem_Loaded;
 7             if (treeViewItem.IsSelected)
 8             {
 9                 treeViewItem.BringIntoView();
10             }
11         }
12     }

此處,對TreeView添加附加屬性處理,也是能夠的htm

虛擬化後的TreeView滾動定位

因開啓了虛擬化,界面上不在當前視覺內的數據項,沒有生成相應的視覺樹,即沒法找到TreeViewItem。blog

因此虛擬化後,使用TreeViewItem添加附加屬性,而不是TreeView。由於TreeView沒法對視覺樹外的項,查找並定位;而TreeViewItem...emmm~能夠使用黑科技處理,詳情以下事件

1. 在上面邏輯的基礎上,添加對虛擬化的處理。get

此處添加了對虛擬化的判斷,虛擬化時若是已經完成了滾動定位,則對後續的邏輯直接跳過,避免選中項的定位被幹擾。

 1     static void OnIsScrolledToViewWhenSelectedChanged(
 2         DependencyObject depObj, DependencyPropertyChangedEventArgs e)
 3     {
 4         if (depObj is TreeViewItem treeViewItem && e.NewValue is bool isIntoViewWhenSelected)
 5         {
 6             treeViewItem.Loaded -= TreeViewItem_Loaded;
 7             //獲取父控件TreeView
 8             var treeView = treeViewItem.FindVisualParent<TreeView>();
 9             if (isIntoViewWhenSelected)
10             {
11                 //開啓了虛擬化且未完成滾動,直接返回
12                 var isOpeningVitualizing = ScrollViewer.GetCanContentScroll(treeView) && VirtualizingPanel.GetIsVirtualizing(treeView);
13                 if (isOpeningVitualizing && GetHasSetSelectedItemVisible(treeView))
14                 {
15                     return;
16                 }
17                 treeViewItem.Loaded += TreeViewItem_Loaded;
18             }
19         }
20     }

2. 在以前邏輯的基礎上,添加虛擬化的判斷

若是開啓了虛擬化,

  • 列表項未選中時,設置滾動到視圖中
  • 列表項選中時,設置已完成,並滾動到視圖中

黑科技:

列表數據加載時,每項都滾動到視圖中。

而虛擬化列表實際上初始化的項個數,在默認設置下,比可視化區域的項個數要多很一部分。

因此在單個數據加載時,設置滾動視圖,會帶動更多本來不在視圖內的數據項,生成視覺樹。

 1     static void TreeViewItem_Loaded(object sender, RoutedEventArgs e)
 2     {
 3         var treeViewItem = e.OriginalSource as TreeViewItem;
 4         if (treeViewItem != null)
 5         {
 6             treeViewItem.Loaded -= TreeViewItem_Loaded;
 7             //獲取父控件TreeView
 8             var treeView = treeViewItem.FindVisualParent<TreeView>();
 9             //是否開啓了虛擬化
10             var isOpeningVirtualizing = ScrollViewer.GetCanContentScroll(treeView) && VirtualizingPanel.GetIsVirtualizing(treeView);
11             if (isOpeningVirtualizing)
12             {
13                 if (treeViewItem.IsSelected)
14                 {
15                     //設置已完成滾動,減小剩餘項的加載判斷
16                     SetHasSetSelectedItemVisible(treeView, true);
17                     treeViewItem.BringIntoView();
18                 }
19                 else
20                 {
21                     treeViewItem.BringIntoView();
22                 }
23             }
24             else if(treeViewItem.IsSelected)
25             {
26                 treeViewItem.BringIntoView();
27             }
28         }
29     }

 WPF 列表開啓虛擬化的方式

關鍵字:TreeView虛擬化、滾動到選中項

相關文章
相關標籤/搜索