WPF MVVM TreeView SelectedItem




(4)

J'ai décidé d'utiliser une combinaison de code derrière et de voir le code de modèle. le xaml est comme ceci:

<TreeView 
                    Name="tvCountries"
                ItemsSource="{Binding Path=Countries}"
                ItemTemplate="{StaticResource ResourceKey=countryTemplate}"   
                    SelectedValuePath="Name"
                    SelectedItemChanged="tvCountries_SelectedItemChanged">

Code derrière

private void tvCountries_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
    {
        var vm = this.FindResource("vm") as ViewModels.CoiEditorViewModel;
        if (vm != null)
        {
            var treeItem = sender as TreeView;
            vm.TreeItemSelected = treeItem.SelectedItem;
        }
    }

Et dans le modèle de vue, il y a un objet TreeItemSelected auquel vous pouvez accéder dans le viewmodel.

Cela ne peut pas être si difficile. TreeView dans WPF ne vous permet pas de définir le SelectedItem, en disant que la propriété est ReadOnly. J'ai le TreeView peuplant, même la mise à jour lorsque sa collection de bases de données est modifiée.

J'ai juste besoin de savoir quel article est sélectionné. J'utilise MVVM, donc il n'y a pas de codebehind ou de variable pour référencer l'arborescence par. C’est la seule solution que j’ai trouvée, mais c’est un piratage évident, elle crée un autre élément dans XAML qui utilise la liaison ElementName pour se positionner sur l’élément sélectionné dans les aperçus, que vous devez ensuite lier à votre ViewModel. Several autres questions sont posées à ce sujet, mais aucune autre solution de travail n'est donnée.

J'ai vu cette question , mais l'utilisation de la réponse donnée me donne des erreurs de compilation, pour une raison quelconque, je ne peux pas ajouter une référence au mélange sdk System.Windows.Interactivity à mon projet. Il dit "erreur inconnue system.windows n'a pas été préchargé" et je n'ai pas encore compris comment y remédier.

Pour les points bonus: pourquoi Microsoft a-t-il rendu la propriété SelectedItem de cet élément ReadOnly?


Un moyen très inhabituel mais très efficace de résoudre ce problème de manière acceptable pour MVVM est le suivant:

  1. Créez un ContentControl réduit par la visibilité sur la même vue que TreeView. Nommez-le de manière appropriée et liez son contenu à une propriété SelectedSomething dans viewmodel. Ce ContentControl "tiendra" l'objet sélectionné et gérera sa liaison, OneWayToSource;
  2. Écoutez SelectedItemChanged dans TreeView et ajoutez un gestionnaire dans code-behind pour définir votre ContentControl.Content sur l'élément nouvellement sélectionné.

XAML:

<ContentControl x:Name="SelectedItemHelper" Content="{Binding SelectedObject, Mode=OneWayToSource}" Visibility="Collapsed"/>
<TreeView ItemsSource="{Binding SomeCollection}"
    SelectedItemChanged="TreeView_SelectedItemChanged">

Code derrière:

    private void TreeView_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
    {
        SelectedItemHelper.Content = e.NewValue;
    }

ViewModel:

    public object SelectedObject  // Class is not actually "object"
    {
        get { return _selected_object; }
        set
        {
            _selected_object = value;
            RaisePropertyChanged(() => SelectedObject);
            Console.WriteLine(SelectedObject);
        }
    }
    object _selected_object;

Vous pouvez toujours créer un DependencyProperty qui utilise ICommand et écouter l'événement SelectedItemChanged sur le TreeView. Cela peut être un peu plus facile que de lier IsSelected, mais j'imagine que vous finirez par lier IsSelected de toute façon pour d'autres raisons. Si vous souhaitez simplement lier IsSelected, vous pouvez toujours envoyer votre message à chaque fois que IsSelected est modifié. Ensuite, vous pouvez écouter ces messages n'importe où dans votre programme.


Utilisez le mode de liaison OneWayToSource . Cela ne fonctionne pas. Voir éditer.

Edit : Il semble que ce soit un bogue ou un comportement "par conception" de Microsoft, selon cette question ; Il existe toutefois des solutions de contournement. Est-ce que l'un de ces éléments fonctionne pour votre TreeView?

Le problème de Microsoft Connect: https://connect.microsoft.com/WPF/feedback/details/523865/read-only-dependency-properties-does-not-support-onewaytosource-bindings

Publié par Microsoft le 10/01/2010 à 14h46

Nous ne pouvons pas faire cela dans WPF aujourd'hui, pour la même raison, nous ne pouvons pas supporter les liaisons sur les propriétés qui ne sont pas DependencyProperties. L'état d'exécution par instance d'une liaison est contenu dans une expression BindingExpression, que nous stockons dans la liste EffectiveValueTable de l'objet DependencyObject cible. Lorsque la propriété cible n'est pas un DP ou que le DP est en lecture seule, il n'y a pas de place pour stocker l'expression BindingExpression.

Il est possible que nous choisissions un jour d’étendre la fonctionnalité de liaison à ces deux scénarios. On nous le demande assez souvent. En d'autres termes, votre demande figure déjà dans notre liste de fonctionnalités à prendre en compte dans les prochaines versions.

Merci pour vos commentaires.





treeview