2009-05-28 12 views
11

En mi vista, tengo un botón.¿Cómo paso la información de View a ViewModel con DelegateCommand?

Cuando el usuario hace clic en este botón, quiero que ViewModel guarde el contexto de TextBlock en la base de datos.

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

Sin embargo, en mi DelegateCommand en mi modelo de vista, la opción "Guardar()" método no pasa ningún argumento, por lo que ¿cómo puedo obtener datos de la vista en ese momento?

#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 

Respuesta

18

Echa un vistazo this MSDN article by Josh Smith. En él, muestra una variación de DelegateCommand que él llama RelayCommand, y los delegados Execute y CanExecute en RelayCommand aceptan un único parámetro de tipo objeto.

Usando RelayCommand puede pasar información a los delegados a través de un CommandParameter:

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

actualización

En cuanto a this article, parece que hay una versión genérica de DelegateCommand que acepta un parámetro en una manera similar. Es posible que desee intentar cambiar su SaveCommand a DelegateCommand<MyObject> y cambiar sus métodos de Guardar y CanSave para que tomen un parámetro MyObject.

+2

De hecho, resolví mi problema vinculando el TextBox a una propiedad de ViewModel (INotifyPropertyChanged), cuyo valor, por supuesto, el comando Save() tiene acceso, pero sus sugerencias son muy interesantes, las verificará. –

+0

Existe un caso de uso específico (y razonablemente común) en el que la solución de Matt definitivamente gana al acceder a un valor límite separado: comandos ejecutados desde un 'ItemsControl'. Aquí, un botón, por ejemplo, en un 'ListView' puede usar su' DataContext' como parámetro y el elemento sobre el que se hizo clic en el botón se pasa junto con el comando. Es difícil determinar en cuál de los muchos elementos se hizo clic de otro modo. –

+1

Tenga en cuenta que el «DelegateCommand» genérico 'tiene una restricción importante (que no se recoge hasta el tiempo de ejecución, el compilador no se queja): no puede usar un tipo de valor como parámetro. El consejo oficial es usar un tipo de valor que admite valores NULL (que está permitido) y verificar antes de su uso que contiene un valor (https://msdn.microsoft.com/en-us/library/gg431410%28v=pandp.50%29 .aspx - ver la sección "Observaciones"). –

9

En su VM:

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

public ICommand SaveCmd{ get{ return _saveCmd } } 

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

En que ver, utilizar CommandParameter como ejemplo de Matt.

+0

No es una respuesta completa, pero esto me indicó la dirección correcta para usar CommandParameter y especificar un tipo para DelegateCommand. Gracias – vdidxho

5

Usted está preguntando sobre la transferencia de datos a través del botón Comando.

lo que realmente quiere, creo, es unen texto de su cuadro de texto a un propiedad pública en su modelo de vista:

<!-- 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

Esto es lo que normalmente hago, ya que el valor de TextBox ya está vinculado a una propiedad en el modelo de vista. No es necesario pasarlo como un parámetro para el comando. –

+0

Tiene más sentido (legibilidad de código) pasarlo como parámetro si usa el texto para un solo propósito. Como, por ejemplo, pasar la clave de activación a su máquina virtual. –

12

aquí es la manera elegante.

dar un nombre a su cuadro de texto, y luego obligar a la CommandParameter en el botón para que la propiedad de texto:

<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

No estoy autorizado para hacer comentarios aún, supongo. Estoy respondiendo a la sugerencia de Carlos porque lo probé. Si bien es una gran idea, DelegateCommand debería modificarse de alguna manera porque de lo contrario obtendrá este error: Un inicializador de campo no puede hacer referencia al campo no estático, método o propiedad 'MyViewModel.Save (cadena)'.

Cuestiones relacionadas