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

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

XML 复制代码
<Window x:Class="WpfApplication2.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <TreeView Name="myTreeView">
            <TreeView.ItemTemplate>
                <HierarchicalDataTemplate ItemsSource="{Binding Children}">
                    <TextBlock Text="{Binding Name}" />
                </HierarchicalDataTemplate>
            </TreeView.ItemTemplate>
        </TreeView>
    </Grid>
</Window>
cs 复制代码
    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<TreeNode> { 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<T> FindLogicalChildren<T>(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<DependencyObject>())
                    foreach (T c in FindLogicalChildren<T>(child))
                        yield return c;
            }
        }



        private void ExpandAndSelect(TreeView treeView, TreeNode targetNode)
        {
            foreach (var node in (ObservableCollection<TreeNode>)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<TreeNode>();
        }
        public string Name { get; set; }
        public ObservableCollection<TreeNode> Children { get; set; }
    }

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

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

cs 复制代码
 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);
        }
相关推荐
明耀10 小时前
WPF C# 用WebView加载H5页面(uniapp项目,vue项目)
uni-app·c#·wpf
白露与泡影1 天前
基于Mongodb的分布式文件存储实现
分布式·mongodb·wpf
Tummer83632 天前
C#+WPF+prism+materialdesign创建工具主界面框架
开发语言·c#·wpf
炯哈哈2 天前
【上位机——WPF】App.xml和Application类简介
xml·开发语言·c#·wpf·上位机
CoderIsArt2 天前
WPF的UI元素类型详解
ui·wpf
zxfgdjfjfjflfllf2 天前
Mapreduce初使用
大数据·wpf·mapreduce
炯哈哈3 天前
【上位机——WPF】Window标签常用属性
开发语言·c#·wpf·上位机
绿龙术士4 天前
构建现代化WPF应用:数据驱动开发与高级特性解析
c#·wpf
wangnaisheng6 天前
【WPF】Opacity 属性的使用
wpf
姬激薄6 天前
配置Hadoop集群-集群配置
wpf