在WPF TreeView中将节点从一个分支移动到另一个分支 - 而不会丢失选择

时间:2013-10-28 11:56:53

标签: wpf treeview

我有一个绑定到可观察集合的树视图。集合中的每个项目都有一个带有项目的可观察集合。

public class Item
{
  public ObservableCollection<Item> Items { get; set; }
  public Item Parent { get; set; }
}

public Item Root { get; set; }

<TreeView ItemsSource={Binding Root.Items}>
   <TreeView.ItemTemplate>
       <HierarchicalDataTemplate ItemsSource="{Binding Items}">
           <TextBlock Text="{Binding}" />
       </HierarchicalDataTemplate>
   </TreeView.ItemTemplate>
</TreeView>

我想将树中的一个节点从一个分支移动到另一个分支,但这样做会使控件松散焦点和选择。

UnindentItemCommand = new DelegateCommand<Item>(
  item => 
  {
     var parent = item.Parent;
     parent.Items.Remove(item);
     parent.parent.Items.Add(item);         
  }
);

我尝试使用another question中的BindableSelectedItemBehavior,但它无济于事。

有人有解决方法吗?

2 个答案:

答案 0 :(得分:1)

如何从视图模型或后面的代码绑定到TreeView.SelectedItem属性?:

<TreeView ItemsSource="{Binding Root.Items}" TreeView.SelectedItem="{Binding Item}">
   <TreeView.ItemTemplate>
       <HierarchicalDataTemplate ItemsSource="{Binding Items}">
           <TextBlock Text="{Binding}" />
       </HierarchicalDataTemplate>
   </TreeView.ItemTemplate>
</TreeView>

然后在您的节点移动代码中,您可以获取所选项目的副本,并在移动数据时重新设置它:

UnindentItemCommand = new DelegateCommand<Item>(
    item => 
    {
        Item selectedItem = Item;
        var parent = item.Parent;
        parent.Items.Remove(item);
        parent.parent.Items.Add(item);
        Item = selectedItem;
    }
);

答案 1 :(得分:0)

我遇到了完全相同的问题。在我看来,这确实是WPF中的错误。移动可观察集合中的节点后,树将正确更新并选择了正确的节点,但是键盘焦点丢失了。对我有用的是,通过获取第一个treeviewitem元素并明确地将焦点设置在树上,来“摇晃”一下树。然后,我将简单地转到我移动的元素,并将IsSelected属性设置为false,然后设置为true,这将使焦点重新回到它上面。这不是最优雅的解决方案,但是与我尝试过的所有其他解决方案相比,它非常简单,并且对最终用户而言看起来都是无缝的。

UnindentItemCommand = new DelegateCommand<Item>(
item => 
{
    Item selectedItem = Item;
    var parent = item.Parent;
    parent.Items.Remove(item);
    parent.parent.Items.Add(item);
    Item = selectedItem;

    TreeViewItem tvi = (TreeViewItem) 
(TreeName.ItemContainerGenerator.ContainerFromItem(TreeName.Items[0]));
    tvi.Focus();
    Keyboard.Focus(tvi);
    Item.IsSelected= false;    
    Item.IsSelected = true;    
}
);


<Style TargetType="{x:Type TreeViewItem}">
   <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />