263 Stimmen

Datenbindung an SelectedItem in einem WPF Treeview

Wie kann ich das Element abrufen, das in einer WPF-Treeview ausgewählt ist? Ich möchte dies in XAML zu tun, weil ich es zu binden möchten.

Man könnte meinen, es sei SelectedItem aber offenbar ist das gibt es nicht ist schreibgeschützt und daher unbrauchbar.

Das ist es, was ich tun möchte:

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

Ich möchte die SelectedItem zu einer Eigenschaft in meinem Modell.

Dies führt jedoch zu einer Fehlermeldung:

Die Eigenschaft "SelectedItem" ist schreibgeschützt und kann nicht über das Markup gesetzt werden.

Editar: Ok, so habe ich das Problem gelöst:

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

und in der Code-Hintergrunddatei meiner Xaml:

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

278voto

Steve Greatrex Punkte 15429

Mir ist klar, dass diese Frage bereits beantwortet wurde, aber ich habe dies zusammengestellt, um das Problem zu lösen. Es verwendet eine ähnliche Idee zu Deltas Lösung, aber ohne die Notwendigkeit, die TreeView Unterklasse:

public class BindableSelectedItemBehavior : Behavior<TreeView>
{
    #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<object> e)
    {
        this.SelectedItem = e.NewValue;
    }
}

Sie können dies dann in Ihrer XAML als verwenden:

<TreeView>
    <e:Interaction.Behaviors>
        <behaviours:BindableSelectedItemBehavior SelectedItem="{Binding SelectedItem, Mode=TwoWay}" />
    </e:Interaction.Behaviors>
</TreeView>

Hoffentlich hilft es jemandem!

46voto

Thomas Levesque Punkte 277723

Diese Eigenschaft ist vorhanden: TreeView.SelectedItem

Sie ist jedoch schreibgeschützt, so dass Sie sie nicht über eine Bindung zuweisen, sondern nur abrufen können.

40voto

Delta Punkte 1970

Nun, ich habe eine Lösung gefunden. Es verschiebt das Chaos, so dass MVVM funktioniert.

Fügen Sie zunächst diese Klasse hinzu:

public class ExtendedTreeView : TreeView
{
    public ExtendedTreeView()
        : base()
    {
        this.SelectedItemChanged += new RoutedPropertyChangedEventHandler<object>(___ICH);
    }

    void ___ICH(object sender, RoutedPropertyChangedEventArgs<object> e)
    {
        if (SelectedItem != null)
        {
            SetValue(SelectedItem_Property, SelectedItem);
        }
    }

    public object SelectedItem_
    {
        get { return (object)GetValue(SelectedItem_Property); }
        set { SetValue(SelectedItem_Property, value); }
    }
    public static readonly DependencyProperty SelectedItem_Property = DependencyProperty.Register("SelectedItem_", typeof(object), typeof(ExtendedTreeView), new UIPropertyMetadata(null));
}

und fügen Sie dies zu Ihrem Xaml hinzu:

 <local:ExtendedTreeView ItemsSource="{Binding Items}" SelectedItem_="{Binding Item, Mode=TwoWay}">
 .....
 </local:ExtendedTreeView>

35voto

JiBéDoublevé Punkte 3946

Es beantwortet ein wenig mehr, als der OP erwartet... Aber ich hoffe, es könnte zumindest jemandem helfen.

Wenn Sie eine ICommand wenn die SelectedItem geändert, können Sie einen Befehl an ein Ereignis und die Verwendung einer Eigenschaft binden SelectedItem im ViewModel wird nicht mehr benötigt.

Um dies zu tun:

1- Verweis hinzufügen auf System.Windows.Interactivity

xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"

2- Binden Sie den Befehl an das Ereignis SelectedItemChanged

<TreeView x:Name="myTreeView" Margin="1"
            ItemsSource="{Binding Directories}">
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="SelectedItemChanged">
            <i:InvokeCommandAction Command="{Binding SomeCommand}"
                                   CommandParameter="
                                            {Binding ElementName=myTreeView
                                             ,Path=SelectedItem}"/>
        </i:EventTrigger>
    </i:Interaction.Triggers>
    <TreeView.ItemTemplate>
           <!-- ... -->
    </TreeView.ItemTemplate>
</TreeView>

21voto

bstoney Punkte 6198

Dies kann auf eine "schönere" Art und Weise erreicht werden, indem man nur die Bindung und die EventToCommand-Funktion der GalaSoft MVVM Light-Bibliothek verwendet. Fügen Sie in Ihrer VM einen Befehl hinzu, der aufgerufen wird, wenn das ausgewählte Element geändert wird, und initialisieren Sie den Befehl, um die erforderliche Aktion durchzuführen. In diesem Beispiel habe ich einen RelayCommand verwendet und werde nur die SelectedCluster-Eigenschaft setzen.

public class ViewModel
{
    public ViewModel()
    {
        SelectedClusterChanged = new RelayCommand<Cluster>( c => SelectedCluster = c );
    }

    public RelayCommand<Cluster> SelectedClusterChanged { get; private set; } 

    public Cluster SelectedCluster { get; private set; }
}

Fügen Sie dann das EventToCommand-Verhalten in Ihre Xaml-Datei ein. Mit Blend ist das wirklich einfach.

<TreeView
      x:Name="lstClusters"
      ItemsSource="{Binding Path=Model.Clusters}" 
      ItemTemplate="{StaticResource HoofdCLusterTemplate}">
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="SelectedItemChanged">
            <GalaSoft_MvvmLight_Command:EventToCommand Command="{Binding SelectedClusterChanged}" CommandParameter="{Binding ElementName=lstClusters,Path=SelectedValue}"/>
        </i:EventTrigger>
    </i:Interaction.Triggers>
</TreeView>

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X