WPF TreeView 虛擬化-設定滾動到選中項
阿新 • • 發佈:2019-06-12
前言
列表滾動到具體的資料項?
ListBox提供了簡易快捷的滾動定位函式ScrollIntoView。
TreeView樹狀結構列表,則沒有此類方法,無法與ListBox一樣,直接設定滾動到具體的資料項。
同時,SelectedItem也是隻讀的,無法設定SelectedItem來間接的設定滾動項。
TreeView滾動定位
1. 對TreeViewItem新增一個附加屬性IsScrolledToViewWhenSelected,在屬性變更事件中,新增對Loaded事件的訂閱和登出
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是否選中,呼叫是否滾動到檢視區域的邏輯
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新增附加屬性處理,也是可以的
虛擬化後的TreeView滾動定位
因開啟了虛擬化,介面上不在當前視覺內的資料項,沒有生成相應的視覺樹,即無法找到TreeViewItem。
所以虛擬化後,使用TreeViewItem新增附加屬性,而不是TreeView。因為TreeView無法對視覺樹外的項,查詢並定位;而TreeViewItem...emmm~可以使用黑科技處理,詳情如下
1. 在上面邏輯的基礎上,新增對虛擬化的處理。
此處添加了對虛擬化的判斷,虛擬化時如果已經完成了滾動定位,則對後續的邏輯直接跳過,避免選中項的定位被幹擾。
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虛擬化、滾動到選