2010-02-15 9 views
9

Je suis occupé à créer ma première application MVVM dans WPF. Fondamentalement, le problème que j'ai est que j'ai un TreeView (System.Windows.Controls.TreeView) que j'ai placé sur ma fenêtre WPF, j'ai décidé que je vais lier à une ReadOnlyCollection des éléments CommandViewModel, et ceux-ci Les éléments sont constitués d'une DisplayString, d'une balise et d'une RelayCommand.WPF: TreeViewItem lié à une ICommand

Maintenant dans le XAML, j'ai mon TreeView et j'ai lié avec succès mon ReadOnlyCollection à ceci. Je peux voir cela et tout semble bien dans l'interface utilisateur.

Le problème est maintenant que j'ai besoin de lier le RelayCommand à la commande du TreeViewItem, mais d'après ce que je peux voir le TreeViewItem n'a pas de commande. Est-ce que cela me force à le faire dans la propriété IsSelected ou même dans le code derrière la méthode TreeView_SelectedItemChanged ou y a-t-il un moyen de le faire par magie dans WPF?

C'est le code que j'ai:

<TreeView BorderBrush="{x:Null}" 
     HorizontalAlignment="Stretch" 
     VerticalAlignment="Stretch"> 
<TreeView.Items> 
    <TreeViewItem 
     Header="New Commands" 
     ItemsSource="{Binding Commands}" 
     DisplayMemberPath="DisplayName" 
     IsExpanded="True"> 
    </TreeViewItem> 
</TreeView.Items> 

et idéalement j'aimerais aller juste:

<TreeView BorderBrush="{x:Null}" 
     HorizontalAlignment="Stretch" 
     VerticalAlignment="Stretch"> 
<TreeView.Items> 
    <TreeViewItem 
     Header="New Trade" 
     ItemsSource="{Binding Commands}" 
     DisplayMemberPath="DisplayName" 
     IsExpanded="True" 
     Command="{Binding Path=Command}"> 
    </TreeViewItem> 
</TreeView.Items> 

Est-ce que quelqu'un a une solution qui me permet utiliser l'infrastructure RelayCommand que j'ai.

Merci les gars, très apprécié!

Richard

Répondre

2

Merci pour l'entrée dans la question, et oui, je ne dis que je ne voulais pas un code derrière solution, mais à ce moment-là j'étais encore beaucoup sous l'impression que je manquais simplement quelque chose ... donc j'ai fini par utiliser l'événement TreeView_SelectedItemChanged.

Même si l'approche de Will semble être un bon travail, pour ma situation personnelle, j'ai décidé que j'utiliserais le code derrière. La raison de ceci est que la vue et XAML resteraient comme si le TreeViewItem avait une propriété "Command" à laquelle ma commande pourrait être liée. Maintenant, je n'ai pas besoin de changer les modèles ou les vues, tout ce que j'ai à faire est d'ajouter le code et l'événement pour TreeView_SelectedItemChanged.

Ma solution:

private void TreeView_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e) 
    { 
     if (sender != null) 
     { 
      var treeView = sender as TreeView; 
      if (treeView != null) 
      { 
       var commandViewModel = treeView.SelectedItem as CommandViewModel; 
       if (commandViewModel != null) 
       { 
        var mi = commandViewModel.Command.GetType().GetMethod("Execute"); 
        mi.Invoke(commandViewModel.Command, new Object[] {null}); 
       } 
      } 
     } 
    } 

Comme je l'ai déjà RelayCommand attaché au TreeViewItem, tout ce que je fais maintenant est d'appeler juste manuellement la méthode « Exécuter » sur cette RelayCommand spécifique.

Si tel est le complètement mauvaise façon d'aller à ce sujet alors s'il vous plaît laissez-moi savoir ...

Merci!

+1

Je crois qu'avec l'arborescence ASP.NET vous pouvez étendre TreeView et TreeViewItem pour ajouter ce genre de fonctionnalité. Vous changeriez le TVI pour ajouter ce dont vous aviez besoin et ensuite remplacer une méthode dans le téléviseur pour créer une nouvelle instance de votre TVI. Je ne sais pas si le même modèle est disponible dans l'arborescence WPF; J'ai vérifié mais pas complètement. – Will

1

Ce que je ferais est mis the Header du TreeViewItem être un bouton, puis écorcher le bouton pour qu'il ne regarde pas ou agir comme un, puis effectuer ma commande de liaison contre le bouton.

Vous devrez peut-être effectuer cette opération via un DataTemplate, ou vous devrez peut-être modifier le modèle de TreeViewItem lui-même. Je ne l'ai jamais fait, mais c'est comme ça que j'ai fait des choses similaires (comme des en-têtes de page à onglets).


Voici un exemple de ce que je parle (vous pouvez déposer cela en Kaxaml et jouer avec elle):

<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> 
    <Page.Resources> 
     <Style x:Key="ClearButan" TargetType="Button"> 
     <Setter Property="Template"> 
      <Setter.Value> 
       <ControlTemplate TargetType="Button">    
       <Border Name="border" 
        Padding="4" 
        Background="transparent"> 
        <Grid > 
        <ContentPresenter HorizontalAlignment="Center" 
            VerticalAlignment="Center"> 
        </ContentPresenter> 
        </Grid> 
       </Border> 
       </ControlTemplate> 
      </Setter.Value> 
     </Setter> 
     </Style> 
    </Page.Resources> 
    <Grid> 
     <TreeView> 
     <TreeViewItem> 
      <Button Style="{StaticResource ClearButan}"> 
      easy peasy 
      </Button> 
     </TreeViewItem> 
     </TreeView> 
    </Grid> 
</Page> 

J'ai créé un nouveau style clair pour un bouton. Je viens ensuite de déposer un bouton dans le TVI et de définir son style. Vous pouvez faire la même chose en utilisant des modèles de données, bien sûr.

+0

Salut, je vois ce que vous essayez de faire, et j'apprécie la réponse rapide, mais est-ce vraiment la meilleure solution? J'ai cherché le net haut et bas et ne peux pas trouver une bonne façon de le faire! Je dois dire que c'est ennuyeux que ce n'est pas seulement intégré. Mais au moins vous avez fourni un moyen de le faire, mais maintenant comment obtenez-vous l'en-tête pour montrer le bouton, et le texte lié? – Richard

+0

@richard mis à jour avec l'échantillon – Will

+1

Merci Will pour la mise à jour et je vois que cela fonctionnerait probablement. Je suis allé un chemin différent, mais j'apprécie beaucoup l'aide. J'espère que cela aidera quelqu'un d'autre qui a ce problème. – Richard

0

Ceci est un bon exemple de la façon dont le MVVM est très après-pensé dans WPF. Vous vous attendez à ce que la commande soit supportée par certains éléments gui, mais ce n'est pas le cas, vous êtes donc obligé de passer par un processus complexe (comme dans l'exemple de Will) juste pour obtenir une commande attachée à quelque chose.

Espérons qu'ils ont incluse dans WPF 2.0 :-)

+4

MVVM est venu après WPF, donc ce n'était pas exactement un "après coup", c'était une façon d'appliquer les principes de MVC à WPF. Aussi, c'est plus d'un défaut de l'arborescence que WPF. Le treeview n'a pas été développé pour ce genre d'utilisation, qui était un peu à court terme imho. – Will

23

Je sais que cela a été "répondu" il ya quelque temps, mais comme les réponses n'étaient pas idéales, j'ai pensé que je mettrais mes deux cents. J'utilise une méthode qui me permet de ne pas avoir à recourir à des "trucs de boutons stylés" ou même d'utiliser du code-behind et conserve à la place toute ma séparation dans MVVM. Dans votre TreeView ajoutez le code XAML suivant:

<i:Interaction.Triggers> 
    <i:EventTrigger EventName="SelectedItemChanged"> 
     <i:InvokeCommandAction Command="{Binding TreeviewSelectedItemChanged}" CommandParameter="{Binding ElementName=treeView, Path=SelectedItem}"/> 
    </i:EventTrigger> 
</i:Interaction.Triggers> 

Dans votre tête XAML ajouter:

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

et vous devrez ajouter une référence à l'assemblage ci-dessus dans votre projet. Après cela, tout se passe exactement comme n'importe quelle autre commande sur un bouton ou quelque chose du genre.

+0

+1 - C'est une excellente réponse car ce n'est pas une solution de code-behind. Cependant, ce n'est pas une solution prête à l'emploi :( – TheCloudlessSky

+0

Est-ce que 'System.Windows.Interactivity' est redistribuable? – AMissico

+0

Oui, voir" C: \ Program Files (x86) \ Microsoft SDKs \ Expression \ Blend \. NETFramework \ v4.0 \ Redist.en.txt ". – AMissico