列表滾動到具體的數據項?html
ListBox提供了簡易快捷的滾動定位函數ScrollIntoView。函數
TreeView樹狀結構列表,則沒有此類方法,沒法與ListBox同樣,直接設置滾動到具體的數據項。post
同時,SelectedItem也是隻讀的,沒法設置SelectedItem來間接的設置滾動項。url
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
因開啓了虛擬化,界面上不在當前視覺內的數據項,沒有生成相應的視覺樹,即沒法找到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 }
關鍵字:TreeView虛擬化、滾動到選中項