不开虚拟化,可以用下面的方法直接定位
- <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>
- 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<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
()) - foreach (T c in FindLogicalChildren<T>(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; } - }
但是如果开了虚拟化,需要默认显示的节点很可能不在可视化树上,所以这套方法就不能用了。
解决办法:计算默认选中项的垂直位置,直接操作滚动条移动到目标节点。
- 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);
- }