2009-02-24 7 views
17

J'utilise le modèle M-V-VM dans une application WPF. Je lie un ViewModel à un ContentControl et utilise un modèle de données défini dans les ressources de la fenêtre pour afficher la vue (un UserControl) pour ce ViewModel.Liaison à une commande dans une grille de données

Dans ViewModel, j'ai une collection d'éléments. Je lie cette collection à la grille de données fournie dans la boîte à outils WPF. Toujours dans le modèle de vue, j'ai une commande RemoveItem définie qui prend un argument pour l'ID d'élément à supprimer.

Comment me lier à cette commande dans la grille de données? Le contexte de données de la grille est cette collection, donc quelque chose comme:

<Button Command="{Binding Path=RemoveCommand}" CommandParameter="{Binding Path=id}">X</Button> 

ne fonctionne pas - il ne trouve pas la commande. Je pense que j'ai besoin de relier RelativeSource, mais à quoi cela ressemblerait-il? Le type Ancêtre serait-il UserControl ou ContentControl? Où se trouve ma ViewModel en tant que DataContext?

Ou suis-je loin?

Répondre

36

Oui, vous avez juste besoin de monter d'un niveau. Je voudrais essayer une liaison avec ElementName d'abord et recourir à RelativeSource seulement si nécessaire. Par exemple, je préfère ceci:

<DataGrid x:Name="_grid"> 
    ... 
     <Button Command="{Binding DataContext.RemoveItem, ElementName=_grid}"/> 
    ... 
</DataGrid> 

Cela dit, le compilateur XAML peut obtenir ses petites culottes dans un nœud en matière de noms d'éléments et portée dans les contrôles, afin que vous puissiez besoin de recourir à un RelativeSource:

<DataGrid x:Name="_grid"> 
    ... 
    <Button Command="{Binding DataContext.RemoveItem, 
        RelativeSource={RelativeSource FindAncestor, 
            AncestorType={x:Type DataGrid}} 
        }"/> 
    ... 
</DataGrid> 

Vous avez seulement besoin de rechercher jusqu'à ce que le contexte de données soit votre modèle de vue. Vous pouvez rechercher un UserControl si vous le souhaitez - pas sûr que cela compte vraiment. Les deux sont des liaisons assez fragiles, c'est pourquoi je préfère l'approche ElementName.

+0

Génial. Merci, Kent! –

+1

Bienvenue. Une autre méthode consiste à exposer une collection de modèles de vue enfants plutôt qu'une collection d'éléments de données. Ensuite, ces modèles de vue enfant peuvent avoir une propriété qui expose la commande, ce qui vous évite d'introduire des liaisons fragiles comme celles-ci. –

+0

Merci, cela a résolu mon problème. –

1

J'aime définir le viewmodel dans datacontext du contrôle avec le nom ViewModel. La liaison est plus facile à écrire en utilisant ElementName

... 
<UserControl.DataContext> 
    <local:UserControlViewModel x:Name="ViewModel"/> 
</UserControl.DataContext> 
... 

... 
<DataGridTemplateColumn Width="30"> 
    <DataGridTemplateColumn.CellTemplate> 
     <DataTemplate> 
      <Button Command="{Binding RemoveCommand, ElementName=ViewModel}" 
        CommandParameter="{Binding}">Remove</Button> 
     </DataTemplate> 
    </DataGridTemplateColumn.CellTemplate> 
</DataGridTemplateColumn> 
... 

Notez que dans ce cas, le paramètre de commande est l'objet de données entier de la ligne. Parfois mieux que

CommandParameter="{Binding Id}" 

parce que vous n'avez pas à trouver de nouvelles données.

Questions connexes