2009-05-28 7 views
11

Dans ma vue, j'ai un bouton.Comment transmettre les informations de View à ViewModel avec DelegateCommand?

Lorsque l'utilisateur clique sur ce bouton, je souhaite que ViewModel enregistre le contexte du TextBlock dans la base de données.

<StackPanel HorizontalAlignment="Left" VerticalAlignment="Top"> 
    <TextBlock Text="{Binding FirstName}"/> 
    <TextBox Text="Save this text to the database."/> 
    <Button Content="Save" Command="{Binding SaveCommand}"/> 
</StackPanel> 

Cependant, dans mon DelegateCommand dans mon ViewModel, la méthode « Save() » ne passe pas d'arguments, alors comment puis-je obtenir des données de la vue à ce moment-là?

#region DelegateCommand: Save 
private DelegateCommand saveCommand; 

public ICommand SaveCommand 
{ 
    get 
    { 
     if (saveCommand == null) 
     { 
      saveCommand = new DelegateCommand(Save, CanSave); 
     } 
     return saveCommand; 
    } 
} 

private void Save() 
{ 
    TextBox textBox = ......how do I get the value of the view's textbox from here?.... 
} 

private bool CanSave() 
{ 
    return true; 
} 
#endregion 

Répondre

18

Découvrez this MSDN article by Josh Smith. Dans celui-ci, il montre une variante de DelegateCommand qu'il appelle RelayCommand, et les délégués Execute et CanExecute sur RelayCommand acceptent un seul paramètre d'objet type.

En utilisant RelayCommand vous pouvez transmettre des informations aux délégués via un CommandParameter:

<Button Command="{Binding SaveCommand}" 
     CommandParameter="{Binding SelectedItem,Element=listBox1}" /> 

Mise à jour

En regardant this article, il semble qu'il existe une version générique de DelegateCommand qui accepte un paramètre d'une manière similaire. Vous pouvez essayer de changer votre SaveCommand en DelegateCommand<MyObject> et modifier vos méthodes Save et CanSave pour qu'elles prennent un paramètre MyObject.

+2

J'ai effectivement résolu mon problème en liant le TextBox à une propriété ViewModel (INotifyPropertyChanged), dont la valeur à laquelle la commande Save() a accès, mais vos suggestions sont très intéressantes, va les vérifier. –

+0

Il existe un cas d'utilisation spécifique (et raisonnablement courant) où la solution de Matt gagne définitivement l'accès à une valeur liée distincte: les commandes exécutées depuis un 'ItemsControl'. Ici, un bouton, par exemple, dans un ListView peut utiliser son paramètre DataContext comme paramètre et l'élément sur lequel le bouton a été cliqué est transmis avec la commande. Il est difficile de déterminer lequel des nombreux éléments a été cliqué sur son bouton. –

+1

Notez que le 'DelegateCommand ' générique a une restriction importante (qui n'est pas détectée avant l'exécution - le compilateur ne se plaindra pas): vous ne pouvez pas utiliser un type de valeur comme paramètre. Le conseil officiel est d'utiliser un type de valeur NULL (qui est autorisé) et vérifiez avant l'utilisation qu'il contient une valeur (https://msdn.microsoft.com/fr-fr/library/gg431410%28v=pandp.50%29 .aspx - voir la section "Remarques"). –

9

Dans votre VM:

private DelegateCommand<string> _saveCmd = new DelegateCommand<string>(Save); 

public ICommand SaveCmd{ get{ return _saveCmd } } 

public void Save(string s) {...} 

En vous, utiliser des plats CommandParameter comme l'exemple de Matt.

+0

Pas une réponse complète mais cela m'a indiqué dans la bonne direction pour utiliser CommandParameter et en spécifiant un type pour DelegateCommand. Merci – vdidxho

5

Vous vous interrogez sur le transfert de données via le bouton Commande.

Qu'est-ce que vous voulez vraiment, je pense, est de lier votre texte de la zone de texte à une propriété publique dans votre ViewModel:

<!-- View: TextBox's text is bound to the FirstName property in your ViewModel --> 
<TextBox Text="{Binding Path=FirstName}" /> 
<Button Command="{Binding SaveCommand}"/> 

<!-- ViewModel: Expose a property for the TextBox to bind to --> 
public string FirstName{ get; set; } 
... 
private void Save() 
{ 
    //textBox's text is bound to --> this.FirstName; 
} 
+0

C'est ce que je fais généralement, puisque la valeur TextBox est déjà liée à une propriété dans le viewmodel. Il n'est pas nécessaire de le passer en paramètre à la commande. –

+0

Il est plus logique (lisibilité du code) de le passer en paramètre si vous n'utilisez le texte que dans un seul but. Comme par exemple passer la clé d'activation à votre machine virtuelle. –

12

est la façon élégante ici.

Donnez un nom à votre zone de texte, puis liez le CommandParameter le bouton à sa propriété Text:

<StackPanel HorizontalAlignment="Left" VerticalAlignment="Top"> 
    <TextBlock Text="{Binding FirstName}"/> 
    <TextBox x:Name="ParameterText" Text="Save this text to the database."/> 
    <Button Content="Save" Command="{Binding SaveCommand}" 
      CommandParameter="{Binding Text, ElementName=ParameterText}"/> 
</StackPanel> 
1

Je ne suis pas autorisé à faire encore de commentaires, je suppose. Je réponds à la suggestion de Carlos parce que je l'ai essayé. Bien que ce soit une excellente idée, DelegateCommand devrait être modifié d'une certaine façon, sinon vous obtiendrez cette erreur: Un initialiseur de champ ne peut pas référencer le champ non statique, la méthode ou la propriété 'MyViewModel.Save (string)'.

Questions connexes