2011-10-05 7 views
5

vi este ejemplo - Binding.UpdateSourceTrigger PropertyConjunto UpdateSourceTrigger a explícita en ShowDialog (WPF MVVM)

en el ejemplo de la UpdateSourceTrigger establece en explícita y luego en el código de la vista que llamar a UpdateSource del nombre de cuadro de texto.

Pero si uso MVVM dp no quiero tener nombres para mis controles y las propiedades de origen están en la VM y no en la vista, ¿cuál es la forma correcta de vincular los controles a las propiedades de la máquina virtual y configurar UpdateSourceTrigger en explícito ?

quiero hacer esto porque en mi caso su ShowDialog ventana y quiero que la fuente se actualizará sólo cuando el usuario pulsa

Gracias de antemano "ok"!

Respuesta

9

Si está utilizando MVVM realmente, su clic de botón Aceptar debe ser manejado por Command. Este comando debe provenir de su ViewModel. Las propiedades enlazadas Expliticly deben provenir de su ViewModel nuevamente. Entonces, ¿qué te detiene?

  1. No utilice Explicit vinculante pero el uso OneWay vinculante.
  2. En su botón, enlace un comando y enlace un parámetro de comando a la propiedad Dependencia limitada OneWay.
  3. En el controlador Execute de su comando (que debe ser algún método de su ViewModel), cambie la propiedad de ViewModel con el parámetro que viene.
  4. Levante el NotifyPropertyChanged para esa propiedad de su ViewModel.

E.g.

Supongamos que necesito actualizar el texto de un cuadro de texto en mi modelo con un clic en el botón Aceptar.

Así que para eso tengo una clase EmployeeViewModel que tiene EmployeeName propiedad en él. La propiedad tiene un getter y un setter. El colocador levanta la notificación de cambio de propiedad. El modelo de vista también tiene otra propiedad de tipo ICommand llamada SaveNameCommand que devuelve un comando para que la ejecute.

EmployeeViewModel es el tipo de contexto de datos de mi vista. Myview tiene un TextBox (denominado como x: Name = "EmployeeNameTxBx") OneWay vinculado al EmployeeName y un botón como OK. Ato la propiedad Button.Command a la propiedad EmployeeViewModel.SaveNameCommand y Button.CommandParameter a la propiedad EmployeeNameTxBx.Text.

 <StackPanel> 
      <TextBox x:Name="EmployeeNameTxBx" 
        Text="{Binding EmployeeName, Mode=OneWay}" /> 
      <Button Content="OK" 
        Command="{Binding SaveNameCommand}" 
        CommandParameter="{Bidning Text, ElementName=EmployeeNameTxBx}" /> 
     </StackPanel> 

Dentro de mi EmployeeViewModel que tienen OnSaveNameCommandExecute(object param) método para ejecutar mi SaveNameCommand.

En este realizar este código ...

 var text = (string)param; 
    this.EmployeeName = text; 

esta manera sólo botón OK clic, actualizaciones de texto del cuadro de texto de nuevo en el EmployeeName propiedad del modelo.

EDITAR

En cuanto a sus comentarios abajo, veo que usted está tratando de implementar la validación de una interfaz de usuario. Ahora esto cambia las cosas un poco.

IDataErrorInfo y la validación relacionada funciona SÓLO SI sus controles de entrada (como cuadros de texto) son TwoWay obligado. Sí, así es como está destinado. Entonces, ahora puede preguntar "¿Esto significa que el concepto de NO PERMITIR que los datos inválidos pasen al modelo es inútil en MVVM si usamos IDataErrorInfo"?

¡No en realidad!

Ver MVVM no hace cumplir una regla que SÓLO los datos válidos deben volver. Acepta datos no válidos y así es como funciona IDataErrorInfo y aumenta la notificación de errores. El punto es ViewModel es una mera softcopy de su Vista por lo que puede ser sucio. Lo que debe asegurarse es que esta suciedad no sea comprometida en sus interfaces externas, como servicios o base de datos.

Este flujo de datos no válidos debe estar restringido por el ViewModel al probar los datos no válidos. Y esa información vendrá si tenemos activado el enlace TwoWay. Entonces, teniendo en cuenta que está implementando IDataErrorInfo, entonces necesita tener enlaces TwoWay, lo cual está perfectamente permitido en MVVM.

Enfoque 1:

¿Qué pasa si wan para validar explícitamente ciertos elementos de la interfaz de usuario de clic de botón?

Para esto, use un truco de validación demorada. En su ViewModel tiene una bandera llamada isValidating. Establecerlo como falso por defecto.

En su propiedad IDataErrorInfo.this omitir la validación mediante la comprobación de la bandera isValidating ...

string IDataErrorInfo.this[string columnName] 
    { 
     get 
     { 
     if (!isValidating) return string.Empty; 

     string result = string.Empty; 
     bool value = false; 

     if (columnName == "EmployeeName") 
     { 
      if (string.IsNullOrEmpty(AccountType)) 
      { 
       result = "EmployeeName cannot be empty!"; 
       value = true; 
      } 
     } 
     return result; 
     } 
    } 

A continuación, en el comando OK ejecutado controlador, compruebe el nombre del empleado y luego subir los eventos de notificación de cambio de propiedad de la misma propiedad ...

private void OnSaveNameCommandExecute(object param) 
    { 
     isValidating = true; 
     this.NotifyPropertyChanged("EmployeeName"); 
     isValidating = false; 
    } 

Esto activa la validación SÓLO al hacer clic en Aceptar. Recuerde que EmployeeName TIENE que contener datos no válidos para que la validación funcione.

Enfoque 2:

¿Qué pasa si quiero actualizar de forma explícita fijaciones sin modo de TwoWay en MVVM?

Luego tendrá que usar Attached Behavior. El comportamiento se adjuntará al botón Aceptar y aceptará una lista de todos los elementos que necesitan que se actualicen sus enlaces.

 <Button Content="OK"> 
      <local:SpecialBindingBehavior.DependentControls> 
       <MultiBinding Converter="{StaticResource ListMaker}"> 
        <Binding ElementName="EmployeeNameTxBx" /> 
        <Binding ElementName="EmployeeSalaryTxBx" /> 
        .... 
       <MultiBinding> 
      </local:SpecialBindingBehavior.DependentControls> 
     </Button> 

El ListMaker es una IMultiValueConverter que simplemente convierte los valores en una lista ...

 Convert(object[] values, ...) 
     { 
      return values.ToList(); 
     } 

En su SpecialBindingBehavior tienen un cambio de manejador DependentControls propiedad ...

 private static void OnDependentControlsChanged(
      DependencyObject depObj, 
      DependencyPropertyChangedEventArgs e) 
     { 
      var button = sender as Button; 
      if (button != null && e.NewValue is IList) 
      { 
       button.Click 
        += new RoutedEventHandler(
         (object s, RoutedEventArgs args) => 
         { 
           foreach(var element in (IList)e.NewValue) 
           { 
           var bndExp 
            = ((TextBox)element).GetBindingExpression(
             ((TextBox)element).Textproperty); 

           bndExp.UpdateSource(); 
           } 
         }); 
      } 
     } 

Pero aún así voy a sugerir que utilice mi anterior MVVM pura basada ** Enfoque 1.

+0

primero gracias por su respuesta detallada! y volviendo a mi problema, estoy usando mvvm puro y tengo comando en mi vm y estoy usando NotifyPropertyChanged. pero si uso el enlace OneWay y tengo en la ventana 10 cuadros de texto significa que necesito enviar los parámetros de comando 10 nombres de elementos? y luego actualizarlos manualmente? no hay forma de usar el enlace ToWay? – Maya

+0

también en este momento estoy usando IDataError para validar el texto en los cuadros de texto, si voy a usar el enlace OneWay ¿puedo todavía validar el texto? – Maya

+0

@Maya, por favor, vea mi naswer editado arriba. –

1

Esta es una vieja pregunta, pero aún así quiero proporcionar un enfoque alternativo para otros usuarios que tropiecen con esta pregunta ... En mis modelos de vista, no expongo las propiedades del modelo directamente en los métodos de propiedad get/set. Yo uso variables internas para todas las propiedades. Luego uniré todas las propiedades en ambos sentidos. Entonces puedo hacer toda la validación como "usual" porque solo se modifican las variables internas. En el constructor del modelo de vista, tengo el objeto modelo como parámetro y establezco las variables internas a los valores de mi modelo. Ahora cuando hago clic en el botón "Guardar" (-> Guardar incendios de comandos en mi modelo de vista se dispara) y no hay errores, configuro todas las propiedades de mi modelo a los valores de la variable interna correspondiente. Si hago clic en "Canel/Deshacer" -Botón (-> Cancelar-Comando en mi modelo de vista se dispara), configuro las variables internas a los valores de mi modelo intacto (usando los ajustadores de las propiedades del modelo de vista para que NotifyPropertyChanged sea llamado y la vista muestra los cambios = valores antiguos).

Otro enfoque más sería implementar Memento-Support en el modelo, por lo que antes de comenzar la edición llame a una función en el modelo para guardar los valores actuales, y si cancela la edición llame a una función para restaurar esos valores. ..de esa forma tendría el soporte para deshacer/cancelar en todas partes y no solo en un modelo de vista ... Implementé ambos métodos en diferentes proyectos y ambos funcionan bien, depende de los requisitos del proyecto ...