WPF Treeview控件开虚拟化后定位节点

作者 : admin 本文共2642个字,预计阅读时间需要7分钟 发布时间: 2024-06-10 共2人阅读

 不开虚拟化,可以用下面的方法直接定位


    
        
            
                
                    
                
            
        
    

    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            
            // 示例数据
            var root = new TreeNode { Name = "Root" };
            for (int i = 0; i < 1000; i++)
            {
                var child = new TreeNode { Name = "Child " + i };
                for (int j = 0; j < 10; j++)
                {
                    child.Children.Add(new TreeNode { Name = "SubChild " + j });
                }
                root.Children.Add(child);
            }

            myTreeView.ItemsSource = new ObservableCollection { root };

            // 等待数据绑定完成后选中并定位到指定节点
            this.Loaded += (s, e) => {
                var nodeToSelect = root.Children[51].Children[5]; // 举例:选中第51个Child的第6个SubChild
                SelectAndScrollToNode(myTreeView, nodeToSelect);
            };
        }

        private void SelectAndScrollToNode(TreeView treeView, TreeNode targetNode)
        {
            // 展开到目标节点
            ExpandAndSelect(treeView, targetNode);
        }

   

        public static IEnumerable FindLogicalChildren(DependencyObject obj) where T : DependencyObject
        {
            if (obj != null)
            {
                if (obj is T)
                    yield return obj as T;
                foreach (DependencyObject child in LogicalTreeHelper.GetChildren(obj).OfType())
                    foreach (T c in FindLogicalChildren(child))
                        yield return c;
            }
        }



        private void ExpandAndSelect(TreeView treeView, TreeNode targetNode)
        {
            foreach (var node in (ObservableCollection)treeView.ItemsSource)
            {
                if (ExpandAndSelectInternal(treeView, node, targetNode))
                    break;
            }
        }

        private bool ExpandAndSelectInternal(ItemsControl parent, TreeNode currentNode, TreeNode targetNode)
        {
            if (currentNode == targetNode)
            {
                if (parent.ItemContainerGenerator.ContainerFromItem(currentNode) is TreeViewItem )
                {
                    var currentItem = parent.ItemContainerGenerator.ContainerFromItem(currentNode) as TreeViewItem;
                    currentItem.IsSelected = true;
                    currentItem.BringIntoView();
                    return true;
                }
            }

            if (parent.ItemContainerGenerator.ContainerFromItem(currentNode) is TreeViewItem)
            {
                var item = parent.ItemContainerGenerator.ContainerFromItem(currentNode) as TreeViewItem;
                item.IsExpanded = true;
                item.UpdateLayout();
                
                foreach (var childNode in currentNode.Children)
                {
                    if (ExpandAndSelectInternal(item, childNode, targetNode))
                    {
                        item.IsExpanded = true;
                        item.UpdateLayout();
                        if (item.ItemContainerGenerator.ContainerFromItem(targetNode) is TreeViewItem )
                        {
                            var targetItem = item.ItemContainerGenerator.ContainerFromItem(targetNode) as TreeViewItem;
                            targetItem.IsSelected = true;
                            targetItem.BringIntoView();
                        }
                        return true;
                    }
                }
            }

            return false;
        }
    }

 
    public class TreeNode
    {
        public TreeNode()
        {
            Children = new ObservableCollection();
        }
        public string Name { get; set; }
        public ObservableCollection Children { get; set; }
    }

WPF Treeview控件开虚拟化后定位节点插图

但是如果开了虚拟化,需要默认显示的节点很可能不在可视化树上,所以这套方法就不能用了。

解决办法:计算默认选中项的垂直位置,直接操作滚动条移动到目标节点。

 private void SelectAndScrollToNode(TreeView treeView, TreeNode targetNode)
        {
            // 展开到目标节点
            ExpandAndSelect(treeView, targetNode);
            //根据targetNode计算滚动条的位置,这里就直接取中间位置了
            TreeViewAutomationPeer lvap = new TreeViewAutomationPeer(treeView);
            var svap = lvap.GetPattern(PatternInterface.Scroll) as ScrollViewerAutomationPeer;
            var scroll = svap.Owner as ScrollViewer;
            double hight = scroll.ScrollableHeight;
            scroll.ScrollToVerticalOffset(hight / 2);
        }

本站无任何商业行为
个人在线分享 » WPF Treeview控件开虚拟化后定位节点
E-->