如何以编程方式选择WPF TreeView中的项目?
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何以编程方式选择WPF TreeView中的项目?相关的知识,希望对你有一定的参考价值。
如何以编程方式选择WPF TreeView
中的项目? ItemsControl
模型似乎阻止了它。
出于某些奇怪的原因,这是一个真正的痛苦,您必须使用ContainerFromItem来获取容器,然后调用select方法。
// selectedItemObject is not a TreeViewItem, but an item from the collection that
// populated the TreeView.
var tvi = treeView.ItemContainerGenerator.ContainerFromItem(selectedItemObject)
as TreeViewItem;
if (tvi != null)
{
tvi.IsSelected = true;
}
曾经有一篇博客文章介绍如何做here,但现在这个链接已经死了。
我创建了一个方法VisualTreeExt.GetDescendants<T>
,它返回一个与指定类型匹配的可枚举元素集合:
public static class VisualTreeExt
{
public static IEnumerable<T> GetDescendants<T>(DependencyObject parent) where T : DependencyObject
{
var count = VisualTreeHelper.GetChildrenCount(parent);
for (var i = 0; i < count; ++i)
{
// Obtain the child
var child = VisualTreeHelper.GetChild(parent, i);
if (child is T)
yield return (T)child;
// Return all the descendant children
foreach (var subItem in GetDescendants<T>(child))
yield return subItem;
}
}
}
当你要求VisualTreeHelperExt.GetDescendants<TreeViewItem>(MyAmazingTreeView)
时,你会得到所有的TreeViewItem
孩子。您可以使用以下代码选择特定值:
var treeViewItem = VisualTreeExt.GetDescendants<TreeViewItem>(MyTreeView).FirstOrDefault(tvi => tvi.DataContext == newValue);
if (treeViewItem != null)
treeViewItem.IsSelected = true;
这是一个肮脏的解决方案(并且可能不是最有效的)并且如果您使用虚拟化TreeView将无法工作,因为它取决于实际视觉元素的存在。但它适用于我的情况......
是的..我知道问题被问到很多年以后但仍然没有快速解决这个问题..所以:
以下将执行OP要求的内容。
我基本上做的是阅读本页面中的所有答案,并遵循所有相关链接,为这个恼人的问题创建一劳永逸的解决方案。
优点:
- 它也支持虚拟化TreeView。
- 它使用行为技术,因此XAML很容易。
- 添加依赖项属性以允许绑定到选定的TreeView项。
这部分是你需要复制的唯一代码,其他部分只是为了帮助完成一个例子。
public static class TreeViewSelectedItemExBehavior
{
private static List<TreeView> isRegisteredToSelectionChanged = new List<TreeView>();
public static readonly DependencyProperty SelectedItemExProperty =
DependencyProperty.RegisterAttached("SelectedItemEx",
typeof(object),
typeof(TreeViewSelectedItemExBehavior),
new FrameworkPropertyMetadata(new object(), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnSelectedItemExChanged, null));
#region SelectedItemEx
public static object GetSelectedItemEx(TreeView target)
{
return target.GetValue(SelectedItemExProperty);
}
public static void SetSelectedItemEx(TreeView target, object value)
{
target.SetValue(SelectedItemExProperty, value);
var treeViewItemToSelect = GetTreeViewItem(target, value);
if (treeViewItemToSelect == null)
{
if (target.SelectedItem == null)
return;
var treeViewItemToUnSelect = GetTreeViewItem(target, target.SelectedItem);
treeViewItemToUnSelect.IsSelected = false;
}
else
treeViewItemToSelect.IsSelected = true;
}
public static void OnSelectedItemExChanged(DependencyObject depObj, DependencyPropertyChangedEventArgs e)
{
var treeView = depObj as TreeView;
if (treeView == null)
return;
if (!isRegisteredToSelectionChanged.Contains(treeView))
{
treeView.SelectedItemChanged += TreeView_SelectedItemChanged;
isRegisteredToSelectionChanged.Add(treeView);
}
}
#endregion
private static void TreeView_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
{
var treeView = (TreeView)sender;
SetSelectedItemEx(treeView, e.NewValue);
}
#region Helper Structures & Methods
public class MyVirtualizingStackPanel : VirtualizingStackPanel
{
/// <summary>
/// Publically expose BringIndexIntoView.
/// </summary>
public void BringIntoView(int index)
{
BringIndexIntoView(index);
}
}
/// <summary>Recursively search for an item in this subtree.</summary>
/// <param name="container">The parent ItemsControl. This can be a TreeView or a TreeViewItem.</param>
/// <param name="item">The item to search for.</param>
/// <returns>The TreeViewItem that contains the specified item.</returns>
private static TreeViewItem GetTreeViewItem(ItemsControl container, object item)
{
if (container != null)
{
if (container.DataContext == item)
{
return container as TreeViewItem;
}
// Expand the current container
if (container is TreeViewItem && !((TreeViewItem)container).IsExpanded)
{
container.SetValue(TreeViewItem.IsExpandedProperty, true);
}
// Try to generate the ItemsPresenter and the ItemsPanel.
// by calling ApplyTemplate. Note that in the
// virtualizing case even if the item is marked
// expanded we still need to do this step in order to
// regenerate the visuals because they may have been virtualized away.
container.ApplyTemplate();
ItemsPresenter itemsPresenter =
(ItemsPresenter)container.Template.FindName("ItemsHost", container);
if (itemsPresenter != null)
{
itemsPresenter.ApplyTemplate();
}
else
{
// The Tree template has not named the ItemsPresenter,
// so walk the descendents and find the child.
itemsPresenter = FindVisualChild<ItemsPresenter>(container);
if (itemsPresenter == null)
{
container.UpdateLayout();
itemsPresenter = FindVisualChild<ItemsPresenter>(container);
}
}
Panel itemsHostPanel = (Panel)VisualTreeHelper.GetChild(itemsPresenter, 0);
// Ensure that the generator for this panel has been created.
UIElementCollection children = itemsHostPanel.Children;
MyVirtualizingStackPanel virtualizingPanel =
itemsHostPanel as MyVirtualizingStackPanel;
for (int i = 0, count = container.Items.Count; i < count; i++)
{
TreeViewItem subContainer;
if (virtualizingPanel != null)
{
// Bring the item into view so
// that the container will be generated.
virtualizingPanel.BringIntoView(i);
subContainer =
(TreeViewItem)container.ItemContainerGenerator.
ContainerFromIndex(i);
}
else
{
subContainer =
(TreeViewItem)container.ItemContainerGenerator.
ContainerFromIndex(i);
// Bring the item into view to maintain the
// same behavior as with a virtualizing panel.
subContainer.BringIntoView();
}
if (subContainer != null)
{
// Search the next level for the object.
TreeViewItem resultContainer = GetTreeViewItem(subContainer, item);
if (resultContainer != null)
{
return resultContainer;
}
else
{
// The object is not under thi以上是关于如何以编程方式选择WPF TreeView中的项目?的主要内容,如果未能解决你的问题,请参考以下文章
python tkinter treeview右键单击(Button-3)事件以选择树视图中的项目
禁用WPF TreeView(或TreeViewItem)选择?
您如何以编程方式将焦点设置到已具有焦点的 WPF ListBox 中的 SelectedItem?