TreeView SelectedItem行为 - 双向绑定在一方向上无法工作

18 浏览
0 Comments

TreeView SelectedItem行为 - 双向绑定在一方向上无法工作

我创建了一个非常简单的示例来展示我的问题。也许我只是以错误的方式思考。

我想选择TreeView中的一个项,并且我希望在视图中看到它(蓝色背景)。

为了实现双向绑定,我使用了这个行为:Data binding to SelectedItem in a WPF Treeview

public class BindableSelectedItemBehavior : Behavior
{
    #region SelectedItem Property
    public object SelectedItem
    {
        get { return (object)GetValue(SelectedItemProperty); }
        set { SetValue(SelectedItemProperty, value); }
    }
    public static readonly DependencyProperty SelectedItemProperty =
        DependencyProperty.Register("SelectedItem", typeof(object), typeof(BindableSelectedItemBehavior), new UIPropertyMetadata(null, OnSelectedItemChanged));
    private static void OnSelectedItemChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
    {
        var item = e.NewValue as TreeViewItem;
        if (item != null)
        {
            item.SetValue(TreeViewItem.IsSelectedProperty, true);
        }
    }
    #endregion
    protected override void OnAttached()
    {
        base.OnAttached();
        this.AssociatedObject.SelectedItemChanged += OnTreeViewSelectedItemChanged;
    }
    protected override void OnDetaching()
    {
        base.OnDetaching();
        if (this.AssociatedObject != null)
        {
            this.AssociatedObject.SelectedItemChanged -= OnTreeViewSelectedItemChanged;
        }
    }
    private void OnTreeViewSelectedItemChanged(object sender, RoutedPropertyChangedEventArgs e)
    {
        this.SelectedItem = e.NewValue;
    }
}

但是,如果我点击一个项,它不会进入OnSelectedItemChanged的 'if' ,因为e.newValue as TreeViewItemnull

我的XAML非常简单:


    
        
            
        
        
            
                
            
        
    
    

谢谢大家!

0
0 Comments

问题原因:OnSelectedItemChanged只会传递一个TreeViewItem类型的对象,如果实际的模型对象不是TreeViewItem类型,那99%的情况下就会出错。如果节点当前是折叠状态,那么无法从模型对象中获取TreeViewItem,这就使得选择折叠节点变得非常棘手。

解决方法:可以参考这篇博文中提供的代码示例(在此处提供了一个链接:here)。

0
0 Comments

这个问题的原因是在`OnSelectedItemChanged`方法中,没有正确地处理树形视图中非根级别的项。因为每个子节点都有自己的`ItemContainerGenerator`,所以需要递归处理。此外,`ItemContainerGenerator`不会立即填充其连接的项,所以需要附加到其`StatusChanged`事件上。解决方法是在`OnSelectedItemChanged`方法中添加递归处理,并在递归中附加到`StatusChanged`事件上。

static void OnSelectedItemChanged(DependencyObject sender, 
  DependencyPropertyChangedEventArgs e)
{
  var behavior = (BindableSelectedItemBehavior)sender;
  var generator = behavior.AssociatedObject.ItemContainerGenerator;
  
  void SetSelectedItem(TreeViewItem item)
  {
    item.SetValue(TreeViewItem.IsSelectedProperty, true);
    if (item.ItemContainerGenerator.Status != GeneratorStatus.ContainersGenerated)
    {
      item.ItemContainerGenerator.StatusChanged += (s, _) =>
      {
        if (item.ItemContainerGenerator.Status == GeneratorStatus.ContainersGenerated)
        {
          foreach (var child in item.ItemContainerGenerator.Items)
          {
            if (item.ItemContainerGenerator.ContainerFromItem(child) is TreeViewItem childItem)
              SetSelectedItem(childItem);
          }
        }
      };
    }
    else
    {
      foreach (var child in item.ItemContainerGenerator.Items)
      {
        if (item.ItemContainerGenerator.ContainerFromItem(child) is TreeViewItem childItem)
          SetSelectedItem(childItem);
      }
    }
  }
  
  if (generator.ContainerFromItem(e.NewValue) is TreeViewItem item)
    SetSelectedItem(item);
}

这样修改后的代码将正确地处理树形视图中非根级别的项。在`SetSelectedItem`方法中,如果`ItemContainerGenerator`的状态不是`GeneratorStatus.ContainersGenerated`,则附加到其`StatusChanged`事件上,并在事件处理程序中递归处理子项。否则,直接递归处理子项。

这样修改后的代码应该能够解决原始问题。

0
0 Comments

问题的原因是,在这种情况下,TreeView的SelectedItem属性不会返回TreeViewItem,而是返回绑定的Items集合中当前选中的项。要从SelectedItem获取TreeViewItem,需要使用ItemContainerGenerator。解决方法如下:

在SelectedItem属性更改的事件处理程序中,使用ItemContainerGenerator的ContainerFromItem方法来获取TreeViewItem。然后,将TreeViewItem的IsSelected属性设置为true,以确保选中状态正确显示。

代码如下:

private static void OnSelectedItemChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
    var behavior = (BindableSelectedItemBehavior)sender;
    var generator = behavior.AssociatedObject.ItemContainerGenerator;
    var item = generator.ContainerFromItem(e.NewValue) as TreeViewItem;
    if (item != null)
    {
        item.SetValue(TreeViewItem.IsSelectedProperty, true);
    }
}

感谢您的回答,问题是由于“generator.ContainerFromItem(e.NewValue)”返回null,因为我的选项卡不处于活动状态。您知道如何解决这个问题吗?

在我的情况下,我正在尝试使用TreeView,并且获取容器也返回null。

0