C# 如何以编程方式选择WPF树视图中的项目?

C# 如何以编程方式选择WPF树视图中的项目?,c#,.net,wpf,treeview,itemscontrol,C#,.net,Wpf,Treeview,Itemscontrol,如何以编程方式在WPFTreeView中选择项目?ItemsControl模型似乎阻止了它。由于一些奇怪的原因,这是一个真正的难题,您必须使用ContainerFromItem获取容器,然后调用select方法 // selectedItemObject is not a TreeViewItem, but an item from the collection that // populated the TreeView. var tvi = treeView.ItemContaine

如何以编程方式在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;
}

曾经有一篇关于如何做的博客文章,但是现在链接已经死了。

你需要获得
树视图项
,然后将
IsSelected
设置为
true

这并不像看起来那么简单,Steven提供的链接在2008年发布了一个解决方案,它可能仍然可以工作,但不能处理虚拟化的TreeView。此外,该条评论中还提到了许多其他问题。没有冒犯,但我也遇到了同样的问题,无法找到完美的解决方案。这里是一些文章/帖子的链接,对我帮助很大-

如何在树视图中展开项目?-第三部分:

以编程方式选择树视图中的项目:

TreeView、TreeView和IsSelected:

对于那些仍在寻找解决此问题的正确方法的人,下面是一个例子。我在Dawander撰写的代码项目文章“WPF TreeView Selection”的评论中找到了这篇文章。 这是由Kenrae于2008年11月25日发布的。这对我很有效。谢谢你,肯瑞

以下是他的帖子: 与其遍历树,不如让您自己的数据对象具有IsSelected属性(我也建议使用IsExpanded属性)。使用TreeView上的ItemContainerStyle属性为树的TreeView项定义样式,该属性将这些属性从TreeView项绑定到数据对象。大概是这样的:

<Style x:Key="LibraryTreeViewItemStyle"
               TargetType="{x:Type TreeViewItem}">
            <Setter Property="IsExpanded"
                        Value="{Binding IsExpanded, Mode=TwoWay}" />
            <Setter Property="IsSelected"
                        Value="{Binding IsSelected, Mode=TwoWay}" />
            <Setter Property="FontWeight"
                        Value="Normal" />
            <Style.Triggers>
                  <Trigger Property="IsSelected"
                              Value="True">
                        <Setter Property="FontWeight"
                                    Value="Bold" />
                  </Trigger>
            </Style.Triggers>
      </Style>

<TreeView ItemsSource="{Binding Path=YourCollection}"
               ItemContainerStyle="{StaticResource LibraryTreeViewItemStyle}"
               ItemTemplate={StaticResource YourHierarchicalDataTemplate}/>
if (_items.Count > 0)
    _treeView.SelectItem(_items[0]);

试试这个

    /// <summary>
    /// Selects the tree view item.
    /// </summary>
    /// <param name="Collection">The collection.</param>
    /// <param name="Value">The value.</param>
    /// <returns></returns>
    private TreeViewItem SelectTreeViewItem(ItemCollection Collection, String Value)
    {
        if (Collection == null) return null;
        foreach(TreeViewItem Item in Collection)
        {
            /// Find in current
            if (Item.Header.Equals(Value))
            {
                Item.IsSelected = true;
                return Item;
            }
            /// Find in Childs
            if (Item.Items != null)
            {
                TreeViewItem childItem = this.SelectTreeViewItem(Item.Items, Value);
                if (childItem != null)
                {
                    Item.IsExpanded = true;
                    return childItem;
                }
            }
        }
        return null;
    }
//
///选择树视图项。
/// 
///收藏。
///价值。
/// 
private TreeViewItem SelectTreeViewItem(ItemCollection集合,字符串值)
{
if(Collection==null)返回null;
foreach(集合中的TreeViewItem项)
{
///在当前找到
if(项目标题等于(值))
{
Item.IsSelected=true;
退货项目;
}
///在孩子身上找到
如果(Item.Items!=null)
{
TreeViewItem childItem=此项。选择TreeViewItem(Item.Items,值);
if(childItem!=null)
{
Item.IsExpanded=true;
返回子项;
}
}
}
返回null;
}

参考资料:

我想我会加入我的解决方案,以防这对任何人都有帮助。请注意,按照kuninl的回答,最好的方法是使用绑定属性,如“IsSelected”,但在我的例子中,它是一个不遵循MVVM的遗留应用程序,因此我最终得出以下结论

private void ChangeSessionSelection()
{
    foreach (SessionContainer item in this.treeActiveSessions.Items)
    {
        var treeviewItem = this.treeActiveSessions.ItemContainerGenerator.ContainerFromItem(item) as TreeViewItem;

        if (item.Session == this.selectedSession.Session)
        {
            treeviewItem.IsSelected = true;
            treeviewItem.IsExpanded = true;
        }
        else
        {
            treeviewItem.IsSelected = false;
            treeviewItem.IsExpanded = false;
        }
    }            
}

这样做的目的是在UI中选择并展开treeview项,该项表示代码隐藏中选定的dataitem。这样做的目的是当用户在同一窗口中的items控件中的选择发生更改时,使treeview中的选择发生更改。

如果要选择包含child的子项的项目,可以使用递归进行选择

public bool Select(TreeViewItem item, object select) // recursive function to set item selection in treeview
{
    if (item == null)
        return false;
    TreeViewItem child = item.ItemContainerGenerator.ContainerFromItem(select) as TreeViewItem;
    if (child != null)
    {
        child.IsSelected = true;
        return true;
    }
    foreach (object c in item.Items)
    {
        bool result = Select(item.ItemContainerGenerator.ContainerFromItem(c) as TreeViewItem, select);
        if (result == true)
            return true;
    }
    return false;
}

我已经创建了一个方法
VisualTreeText.GetDescents
,该方法返回与指定类型匹配的元素的可枚举集合:

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;
    }
  }
}

这是一个有点脏的解决方案(可能不是最有效的),如果您使用虚拟化的TreeView,它将不起作用,因为它取决于实际视觉元素的存在。但它适用于我的情况…

我成功地使用了以下代码:

public static TreeViewItem FindTviFromObjectRecursive(ItemsControl ic, object o) {
  //Search for the object model in first level children (recursively)
  TreeViewItem tvi = ic.ItemContainerGenerator.ContainerFromItem(o) as TreeViewItem;
  if (tvi != null) return tvi;
  //Loop through user object models
  foreach (object i in ic.Items) {
    //Get the TreeViewItem associated with the iterated object model
    TreeViewItem tvi2 = ic.ItemContainerGenerator.ContainerFromItem(i) as TreeViewItem;
    tvi = FindTviFromObjectRecursive(tvi2, o);
    if (tvi != null) return tvi;
  }
  return null;
}
用法:

var tvi = FindTviFromObjectRecursive(TheTreeView, TheModel);
if (tvi != null) tvi.IsSelected = true;
    private void ClearSelectedItem()
    {
        if (AssetTreeView.SelectedItem != null)
        {
            DeselectTreeViewItem(AssetTreeView.Items.Cast<TreeViewItem>());
        }
    }

嗯。。我知道这个问题已经问了很多年了,但是。。这个问题仍然没有快速的解决办法。。因此:

下面将执行OP要求的操作

基本上,我所做的是阅读本页中的所有答案,并按照所有相关链接创建一个一劳永逸的解决这个恼人问题的方法

好处:

  • 它还支持虚拟化TreeView
  • 它使用行为技术,因此XAML非常简单
  • 添加依赖性属性以允许绑定到选定的TreeView项
这部分是您需要复制的唯一代码,其他部分只是为了帮助完成一个示例

公共静态类TreeViewSelectedItemExBehavior
{
私有静态列表isRegisteredToSelectionChanged=新列表();
公共静态只读从属属性SelectedExproperty=
DependencyProperty.RegisterAttached(“SelectedItemEx”,
类型(对象),
类型(TreeViewSelectedItemExBehavior),
新建FrameworkPropertyMetadata(新建对象(),FrameworkPropertyMetadata选项.bindstwoway默认,onSelectedItemExchange,null));
#区域选择编辑
公共静态对象GetSelectedItemEx(TreeView目标)
{
返回target.GetValue(SelectedItemExProperty);
}
公共静态void SetSelectedItemEx(TreeView目标,对象值)
{
target.SetValue(SelectedItemExProperty,value);
var treeViewItemToSelect=GetTreeViewItem(目标,值);
if(treeViewItemToSelect==null)
{
如果(target.SelectedItem==null)
返回;
var treeViewItemToUnSelect=GetTreeViewItem(target,target.SelectedItem);
treeViewItemToUnSelect.isselect=false;
}
其他的
treeViewItemToSelect.IsSelected=true;
}
SelectedItemExchange上的公共静态无效(DependencyObject depObj、DependencyPropertyChangedEventArgs e)
{
var treeView=depObj作为treeView;
if(treeView==null)
返回;
如果(
if (_items.Count > 0)
    _treeView.SelectItem(_items[0]);
if (TreeView1.Items.Count > 0)
        (TreeView1.Items[0] as TreeViewItem).IsSelected = true;
private void MouseDownEventProcessing(TreeNodeMouseClickEventArgs e)
{
    tvEmployeeDirectory.SelectedNode = e.Node;
}
    private static void DeselectTreeViewItem(IEnumerable<TreeViewItem> treeViewItems)
    {
        foreach (var treeViewItem in treeViewItems)
        {
            if (treeViewItem.IsSelected)
            {
                treeViewItem.IsSelected = false;
                return;
            }

            DeselectTreeViewItem(treeViewItem.Items.Cast<TreeViewItem>());
        }
    }
    private void ClearSelectedItem()
    {
        if (AssetTreeView.SelectedItem != null)
        {
            DeselectTreeViewItem(AssetTreeView.Items.Cast<TreeViewItem>());
        }
    }
    TreeViewItem FindTreeViewItem( Stack<object> nodeStack, TreeView treeView )
    {
        ItemsControl itemsControl = treeView;

        while (nodeStack.Count > 0) {
            object node = nodeStack.Pop();
            bool found = false;

            foreach (object item in itemsControl.Items) {
                if (item == node) {
                    found = true;

                    if (itemsControl.ItemContainerGenerator.ContainerFromItem( item ) is TreeViewItem treeViewItem) {
                        if (nodeStack.Count == 0) {
                            return treeViewItem;
                        }

                        itemsControl = treeViewItem;
                        treeViewItem.IsExpanded = true;
                        treeViewItem.UpdateLayout();
                        break;
                    }
                }
            }

            if (!found) {
                return null;
            }
        }

        return null;
    }
    // Build nodeStack here from your data

    TreeViewItem treeViewItem = FindTreeViewItem( nodeStack, treeView );

    if (treeViewItem != null) {
        treeViewItem.IsSelected = true;
        treeViewItem.BringIntoView();
    }
public class TreeViewHelper<TModel>
{
    public TreeViewHelper(TreeView treeView, Func<TModel, TModel> getParent, Func<TModel, IList<TModel>> getSubItems)
    {
        TreeView = treeView;
        GetParent = getParent;
        GetSubItems = getSubItems;
    }

    public TreeView TreeView { get; }
    public Func<TModel, TModel> GetParent { get; }
    public Func<TModel, IList<TModel>> GetSubItems { get; }

    public void SelectItemWhileLoaded(TModel node, IList<TModel> rootNodes)
    {
        if (TreeView.IsLoaded)
        {
            SelectItem(node, rootNodes);
        }
        else
        {
            TreeView.Loaded += TreeView_Loaded;
            void TreeView_Loaded(object sender, System.Windows.RoutedEventArgs e)
            {
                TreeView.Loaded -= TreeView_Loaded;
                SelectItem(node, rootNodes);
            }
        }
    }


    public void SelectItem(TModel node, IList<TModel> rootNodes)
    {
        Stack<TModel> nodes = new Stack<TModel>();
        //push into stack
        while (!rootNodes.Contains(node))
        {
            nodes.Push(node);
            node = GetParent(node);
        }
        TreeViewItem treeViewItem = TreeView.ItemContainerGenerator
            .ContainerFromItem(node) as TreeViewItem;
        if (nodes.Count == 0)
        {
            //Top level
            treeViewItem.IsSelected = true;
            treeViewItem.BringIntoView();
            return;
        }
        Expanded(true);
        void Expanded(bool top)
        {
            if (!top)
            {
                treeViewItem = treeViewItem.ItemContainerGenerator
                    .ContainerFromItem(node) as TreeViewItem;
                if (nodes.Count == 0)
                {
                    treeViewItem.IsSelected = true;
                    treeViewItem.BringIntoView();
                    return;
                }
            }
            node = nodes.Pop();
            treeViewItem.IsExpanded = true;
            if (treeViewItem.ItemContainerGenerator.Status == GeneratorStatus.ContainersGenerated)
            {
                Expanded(true);
            }
            else
            {
                //Lazy
                treeViewItem.ItemContainerGenerator.StatusChanged += ItemContainerGenerator_StatusChanged;
            }
        }
        void ItemContainerGenerator_StatusChanged(object sender, EventArgs e)
        {
            if (treeViewItem.ItemContainerGenerator.Status == GeneratorStatus.ContainersGenerated)
            {
                treeViewItem.ItemContainerGenerator.StatusChanged -= ItemContainerGenerator_StatusChanged;
                Expanded(false);
            }
        }
    }
}