如何检索在WPF-treeview中选择的项?我想在XAML中这样做,因为我想绑定它。

您可能认为它是SelectedItem,但显然它不存在是只读的,因此不可用。

这就是我想做的:

<TreeView ItemsSource="{Binding Path=Model.Clusters}" 
            ItemTemplate="{StaticResource ClusterTemplate}"
            SelectedItem="{Binding Path=Model.SelectedCluster}" />

我想将SelectedItem绑定到我的Model上的一个属性。

但这给了我一个错误:

“SelectedItem”属性是只读的,不能从标记中设置。

编辑: 这就是我解决这个问题的方法:

<TreeView
          ItemsSource="{Binding Path=Model.Clusters}" 
          ItemTemplate="{StaticResource HoofdCLusterTemplate}"
          SelectedItemChanged="TreeView_OnSelectedItemChanged" />

在我的xaml的代码背后文件:

private void TreeView_OnSelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
{
    Model.SelectedCluster = (Cluster)e.NewValue;
}

当前回答

也可以使用TreeView项的IsSelected属性来完成。我是这么做的,

public delegate void TreeviewItemSelectedHandler(TreeViewItem item);
public class TreeViewItem
{      
  public static event TreeviewItemSelectedHandler OnItemSelected = delegate { };
  public bool IsSelected 
  {
    get { return isSelected; }
    set 
    { 
      isSelected = value;
      if (value)
        OnItemSelected(this);
    }
  }
}

然后在包含TreeView绑定到的数据的ViewModel中,只需订阅TreeViewItem类中的事件。

TreeViewItem.OnItemSelected += TreeViewItemSelected;

最后,在同一个ViewModel中实现这个处理器,

private void TreeViewItemSelected(TreeViewItem item)
{
  //Do something
}

当然,绑定,

<Setter Property="IsSelected" Value="{Binding IsSelected}" />    

其他回答

这个属性存在:TreeView。设置SelectedItem

但是它是只读的,所以你不能通过绑定来赋值它,只能检索它

走吧

... 是一个更好的答案,但没有提到一种在ViewModel中获取/设置SelectedItem的方法。

添加一个IsSelected布尔属性到ItemViewModel,并在TreeViewItem的样式设置器中绑定到它。 在ViewModel中添加SelectedItem属性,作为TreeView的DataContext。这是上面解决方案中缺少的部分。

    ' ItemVM...
    Public Property IsSelected As Boolean
        Get
            Return _func.SelectedNode Is Me
        End Get
        Set(value As Boolean)
            If IsSelected  value Then
                _func.SelectedNode = If(value, Me, Nothing)
            End If
            RaisePropertyChange()
        End Set
    End Property
    ' TreeVM...
    Public Property SelectedItem As ItemVM
        Get
            Return _selectedItem
        End Get
        Set(value As ItemVM)
            If _selectedItem Is value Then
                Return
            End If
            Dim prev = _selectedItem
            _selectedItem = value
            If prev IsNot Nothing Then
                prev.IsSelected = False
            End If
            If _selectedItem IsNot Nothing Then
                _selectedItem.IsSelected = True
            End If
        End Set
    End Property
<TreeView ItemsSource="{Binding Path=TreeVM}" 
          BorderBrush="Transparent">
    <TreeView.ItemContainerStyle>
        <Style TargetType="TreeViewItem">
            <Setter Property="IsExpanded" Value="{Binding IsExpanded}"/>
            <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}"/>
        </Style>
    </TreeView.ItemContainerStyle>
    <TreeView.ItemTemplate>
        <HierarchicalDataTemplate ItemsSource="{Binding Children}">
            <TextBlock Text="{Binding Name}"/>
        </HierarchicalDataTemplate>
    </TreeView.ItemTemplate>
</TreeView>

我建议对Steve Greatrex提供的行为进行补充。他的行为并不反映来自源的更改,因为它可能不是TreeViewItems的集合。 所以这是一个在树中找到TreeViewItem的问题,它的数据上下文是来自源的selectedValue。 TreeView有一个名为“ItemsHost”的受保护属性,它包含TreeViewItem集合。我们可以通过反射获得它,并遍历树搜索所选项目。

private static void OnSelectedItemChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
    {
        var behavior = sender as BindableSelectedItemBehaviour;

        if (behavior == null) return;

        var tree = behavior.AssociatedObject;

        if (tree == null) return;

        if (e.NewValue == null) 
            foreach (var item in tree.Items.OfType<TreeViewItem>())
                item.SetValue(TreeViewItem.IsSelectedProperty, false);

        var treeViewItem = e.NewValue as TreeViewItem; 
        if (treeViewItem != null)
        {
            treeViewItem.SetValue(TreeViewItem.IsSelectedProperty, true);
        }
        else
        {
            var itemsHostProperty = tree.GetType().GetProperty("ItemsHost", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);

            if (itemsHostProperty == null) return;

            var itemsHost = itemsHostProperty.GetValue(tree, null) as Panel;

            if (itemsHost == null) return;

            foreach (var item in itemsHost.Children.OfType<TreeViewItem>())
                if (WalkTreeViewItem(item, e.NewValue)) break;
        }
    }

    public static bool WalkTreeViewItem(TreeViewItem treeViewItem, object selectedValue) {
        if (treeViewItem.DataContext == selectedValue)
        {
            treeViewItem.SetValue(TreeViewItem.IsSelectedProperty, true);
            treeViewItem.Focus();
            return true;
        }

        foreach (var item in treeViewItem.Items.OfType<TreeViewItem>())
            if (WalkTreeViewItem(item, selectedValue)) return true;

        return false;
    }

这种方式的行为适用于双向绑定。或者,也可以将ItemsHost获取移动到Behavior的OnAttached方法,从而节省每次绑定更新时使用反射的开销。

你也可以使用TreeViewItem。IsSelected财产

在学习了一天的互联网后,我找到了自己的解决方案,在一个普通的WPF/ c#环境中创建一个普通的树视图后选择一个项目

private void BuildSortTree(int sel)
        {
            MergeSort.Items.Clear();
            TreeViewItem itTemp = new TreeViewItem();
            itTemp.Header = SortList[0];
            MergeSort.Items.Add(itTemp);
            TreeViewItem prev;
            itTemp.IsExpanded = true;
            if (0 == sel) itTemp.IsSelected= true;
            prev = itTemp;
            for(int i = 1; i<SortList.Count; i++)
            {

                TreeViewItem itTempNEW = new TreeViewItem();
                itTempNEW.Header = SortList[i];
                prev.Items.Add(itTempNEW);
                itTempNEW.IsExpanded = true;
                if (i == sel) itTempNEW.IsSelected = true;
                prev = itTempNEW ;
            }
        }