2009-05-28 14 views
11

Nella mia vista, ho un pulsante.Come passare le informazioni da Visualizza a ViewModel con DelegateCommand?

Quando l'utente fa clic su questo pulsante, voglio che ViewModel salvi il contesto di TextBlock nel database.

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

Tuttavia, a mio DelegateCommand nel mio ViewModel, il "Save()" il metodo non passa alcun argomento, così come faccio ad ottenere i dati dal punto di vista in quel punto?

#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 

risposta

18

Check out this MSDN article by Josh Smith. In esso, mostra una variazione di DelegateCommand che chiama RelayCommand ei delegati Execute e CanExecute su RelayCommand accettano un singolo parametro di tipo object.

Usando RelayCommand è possibile passare le informazioni ai delegati tramite un CommandParameter:

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

Aggiornamento

Guardando this article, sembra che ci sia una versione generica del DelegateCommand che accetta un parametro in un modo simile. Potresti provare a cambiare il tuo SaveCommand su un DelegateCommand<MyObject> e modificare i metodi Save e CanSave in modo che prendano un parametro MyObject.

+2

In realtà ho risolto il problema collegando TextBox a una proprietà ViewModel (INotifyPropertyChanged), il valore di cui ovviamente il comando Salva() ha accesso, ma i vostri suggerimenti sono molto interessanti, li verificheranno. –

+0

C'è un caso d'uso specifico (e ragionevolmente comune) in cui la soluzione di Matt vince sicuramente per l'accesso a un valore associato separato: comandi eseguiti all'interno di un 'ItemsControl'. Qui, un pulsante, ad esempio, in un 'ListView' può usare il suo' DataContext' come parametro e l'elemento su cui è stato fatto clic sul pulsante viene passato insieme al comando. È difficile capire a quale dei molti elementi è stato fatto clic sul pulsante in caso contrario. –

+1

Si noti che il generico 'DelegateCommand ' ha una restrizione importante (che non viene rilevata fino al runtime - il compilatore non si lamenterà): non è possibile utilizzare un tipo di valore come parametro. Il consiglio ufficiale è di usare un tipo di valore nullable (che è permesso) e controllare prima dell'uso che contenga un valore (https://msdn.microsoft.com/en-us/library/gg431410%28v=pandp.50%29 .aspx - vedere la sezione "Osservazioni"). –

9

Nel vostro VM:

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

public ICommand SaveCmd{ get{ return _saveCmd } } 

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

In te vista, utilizzare CommandParameter come esempio di Matt.

+0

Non è una risposta completa ma questo mi ha indirizzato nella giusta direzione per l'utilizzo di CommandParameter e per specificare un tipo per DelegateCommand. Grazie – vdidxho

5

Stai chiedendo di passare i dati tramite il pulsante Comando.

quello che realmente vuole, credo, è quello di legano testo di vostra casella di testo a una proprietà pubblica nel vostro 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

Questo è ciò che faccio in genere, poiché il valore TextBox è già associato a una proprietà nel viewmodel. Non è necessario passarlo come parametro al comando. –

+0

Ha più senso (leggibilità del codice) passarlo come parametro se si utilizza il testo per un solo scopo. Ad esempio, il passaggio della chiave di attivazione alla tua VM. –

12

qui è il modo elegante.

dare un nome alla vostra casella di testo, quindi associare il CommandParameter nel pulsante alla sua proprietà 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

io non sono autorizzato a fare ancora commenti, immagino. Sto rispondendo al suggerimento di Carlos perché l'ho provato. Sebbene sia una buona idea, DelegateCommand dovrebbe essere modificato in qualche modo perché altrimenti si otterrà questo errore: Un inizializzatore di campo non può fare riferimento al campo, al metodo o alla proprietà non statici "MyViewModel.Save (stringa)".

Problemi correlati