2010-11-11 12 views
15

Estamos tratando de averiguar la validación en el mvvm haciendo la validación en la lógica o modelo de negocio. He implementado la validación según el tipo de excepción en nuestra lógica de negocio - un esquema simplificado se puede encontrar aquí: alt textMVVM - Validación

Si tenemos mucho de la de los insumos que son independientes entre sí, no hay problema, el se lanza una excepción, el cuadro de texto lo atrapa y marca las fronteras rojas para cada entrada incorrecta. Sin embargo, cuando tenemos valores dependientes, tenemos problemas. p.

  • Valor1 y Valor2 en el modelo no debe ser el mismo, así que tenemos una función de validación en cada uno de aquellos que buscan el valor iguales y lanzar una excepción si eso sucede

  • ahora, si establecemos Value1 en 0 y Value2 en 1 todo está bien

  • El valor 1 se establece en la GUI para 1 -> este se marca en rojo, porque la validación de los otros valores no se activa, por lo que Value2 en La GUI no está marcada como defectuosa

  • Valor2 se establece en 2 en la interfaz gráfica de usuario, ahora hemos llegado a un estado válido, pero sólo Valor2 se validó, por lo Valor1 todavía está marcada como defectuosa

¿Hay un patrón común de resolver ese problema? no queremos introducir una dependencia en la GUI entre las dos cajas de texto, porque esta lógica solo debería estar presente en la capa de lógica de negocios.

En lugar de implementar la validación por excepción también se podría implementar la interfaz IDataErrorInfo, pero todavía existe el problema, no hay manera de forzar a los valores en función de validar sus valores de nuevo, al menos ninguno que yo pueda ver :)

Cualquier ayuda se agradece

alegrías, manni


[limpieza, retira paso unecessary]


15.11.2010 - Parte 2

bien, gran repensado aquí, vamos con el nivel BusinessLogic. aquí está nuestra configuración planificada actual: alt text (la imagen es un poco pequeña a escala aquí, por favor ábrala en una ventana separada para mostrarla en tamaño completo) todo está más o menos claro, excepto cómo notificar a todos los modelos de vista/clones modelo de los diferentes editores si se cambia el modelo de datos bajo la lógica comercial. Una forma de hacerlo es rastrear los modelos clonados en la lógica de negocios que los crea. Cuando se modifique el modelo de datos utilizando la lógica de negocios commit(), todos los demás clones de modelos registrados podrán ser notificados de los cambios y propagarlos aún más. alternativamente, la lógica comercial podría publicar un evento al que se suscriban todos los modelos de vista para que también puedan obtener los cambios. ¿Alguien podría darme una pista de qué es mejor?

Gracias de nuevo por la ayuda, lo siento Estoy tan mente bloqueada;)

+0

¿Por qué los valores de las propiedades de configuración de VM en la capa empresarial? Esta parece ser la causa raíz de algunos de sus problemas. Todos (parece) tienen una interpretación ligeramente diferente de lo que significa MVVM, pero en mi humilde opinión el modelo es una combinación de un modelo de datos y controlador, por lo que contiene un superconjunto de los datos en la VM y coordina el acceso a servicios web/repositorios/etc. . Por lo tanto, su capa de negocios existente debe incorporarse en el modelo actual o posiblemente moverse después del modelo (es decir, del otro lado de un límite de WCF). – slugster

+0

estamos pensando en colapsar el Modelo (que es nuestro modelo de datos) y BusinessLogic en una capa, que es esencialmente lo que quiere decir si lo entendiera correctamente. pero aun así creo que el vm no debe contener la validación. Pero aún así el problema del paso de cuerdas continúa. Al mover la lógica de negocios al otro lado de un límite wcf, ¿implicaría eso que todo el modelo es simplemente un titular de datos estúpido que puede editarse y enviarse como un todo a la lógica comercial y evaluarse allí? ¿tiene algún vínculo con respecto al uso de un límite wcf y la división? gracias por la ayuda – manni

+0

Absolutamente haces la validación en la máquina virtual, pero es una validación simple, como * la contraseña es más larga que 6 caracteres * o * la dirección de correo electrónico es un formato válido *. Si desea mantener su lógica comercial desacoplada del modelo, considere utilizar un enfoque de n niveles para el repositorio de datos model-> business logic-> (es común que el BL y la capa de datos se incorporen en un servicio web, pero no tiene que ser así si solo está usando una base de datos local). Tener el BL en el modelo sigue siendo una mejor opción de lo que tienes actualmente. – slugster

Respuesta

15

Se podría considerar el uso de la interfaz System.ComponentModel.IDataErrorInfo.Esta interfaz muy práctica le da la capacidad de:

  • hacer la validación en un MVVM manera compatible
  • hacer una validación personalizada para cualquier campo en particular (la validación puede comprobar varios valores si quieres que)
  • se unen su UI a los errores de validación

Implementa IDataErrorInfo en su modelo de vista (o incluso virtualmente en su base de modelo de vista, y lo anula en sus modelos de vista derivados). Debido a la naturaleza de la vinculación de datos, los valores que debo verificar están todos en el modelo de vista, y puedo probar cualquier combinación de ellos. Por supuesto, todavía tiene su validación en la capa de su empresa, pero ya no necesita hacer un viaje a su capa de negocios (o Modelo) solo para realizar alguna validación.

Aquí está un ejemplo rápido de una pantalla (WPF) que reúne algunos detalles del usuario y hace la validación básica sobre ellos:

código C#:

#region IDataErrorInfo Members 

    /// <summary> 
    /// Gets an error message indicating what is wrong with this object. 
    /// </summary> 
    /// <value></value> 
    /// <returns>An error message indicating what is wrong with this object. The default is an empty string ("").</returns> 
    public override string Error 
    { 
     get 
     { 
      return this["UserCode"] + this["UserName"] + this["Password"] + this["ConfirmedPassword"] + this["EmailAddress"]; 
     } 
    } 

    /// <summary> 
    /// Gets the <see cref="System.String"/> with the specified column name. 
    /// </summary> 
    /// <value></value> 
    public override string this[string columnName] 
    { 
     get 
     { 
      switch (columnName) 
      { 
       case "UserCode": 
        if (!string.IsNullOrEmpty(UserCode) && UserCode.Length > 20) 
         return "User Code must be less than or equal to 20 characters"; 
        break; 

       case "UserName": 
        if (!string.IsNullOrEmpty(UserCode) && UserCode.Length > 60) 
         return "User Name must be less than or equal to 60 characters"; 
        break; 

       case "Password": 
        if (!string.IsNullOrEmpty(Password) && Password.Length > 60) 
         return "Password must be less than or equal to 60 characters"; 
        break; 

       case "ConfirmedPassword": 
        if (Password != ConfirmedPassword) 
         return Properties.Resources.ErrorMessage_Password_ConfirmedPasswordDoesntMatch; 
        break; 

       case "EmailAddress": 
        if (!string.IsNullOrEmpty(EmailAddress)) 
        { 
         var r = new Regex(_emailRegex); 
         if (!r.IsMatch(EmailAddress)) 
          return Properties.Resources.ErrorMessage_Email_InvalidEmailFormat; 
        } 
        break; 
      } 
      return string.Empty; 
     } 
    } 

    #endregion 

y aquí está el marcado XAML para dos de los cuadros de texto en la página (nota particularmente los ValidatesOnDataErrors y ValidatesOnExceptions propiedades en la Text vinculantes):

<TextBox Name="UserCodeTextBox" 
     Text="{Binding UserCode, 
       Mode=TwoWay, 
       UpdateSourceTrigger=PropertyChanged, 
       ValidatesOnDataErrors=True, 
       ValidatesOnExceptions=True, 
       NotifyOnSourceUpdated=True, 
       NotifyOnTargetUpdated=True}" 
     GotFocus="Input_GotFocus" 
     VerticalAlignment="Top" 
     Margin="165,0,150,0" 
     CharacterCasing="Upper" 
     /> 

<TextBox Name="UserNameTextBox" 
     Text="{Binding UserName, 
       Mode=TwoWay, 
       UpdateSourceTrigger=PropertyChanged, 
       ValidatesOnDataErrors=True, 
       ValidatesOnExceptions=True, 
       NotifyOnSourceUpdated=True, 
       NotifyOnTargetUpdated=True}" 
     GotFocus="Input_GotFocus" 
     VerticalAlignment="Top" 
     Margin="165,30,0,0" 
     /> 
+0

gracias por la respuesta detallada. es muy diferente al enfoque excepción, ya que con la interfaz IDataErrorInfo que esencialmente - establecer el valor - comprobar si el objeto está en un estado válido esto significa que entre medio se obtiene un objeto con un estado no válido este está bien si tiene un botón confirmar/guardar y está trabajando en un clon desde el modelo, pero ir directamente al modelo con un estado inválido es un poco peligroso – manni

+0

@user Los datos nunca llegarán al modelo de vista en este ejemplo si la validación falla El enlace validará primero y luego rechazará los datos antes de que se vincule con el modelo de vista. –

+1

@josh: dado que la línea este método [cadena] toma el nombre de propiedad y accede a su propio miembro con ese nombre, ese miembro tiene que tener el nuevo valor no válido, de lo contrario esa verificación no se puede realizar (y se haría a la antigua valor) - o me falta algo aquí? – manni

0

¿Existe un patrón común para resolver ese problema? no queremos introducir una dependencia en la GUI entre las dos cajas de texto, porque esta lógica solo debería estar presente en la capa de lógica de negocios.

  1. Value1 y Value2 son interdependientes debido a la condición "valor1 y valor2 en el modelo no debe ser el mismo".

  2. Esto significa que cuando Value2 cambia, Value1 también cambia, y viceversa! En realidad, cuando Value2 cambia, el resultado de la validación Value1 cambia, pero está cerca de la declaración anterior.

  3. Value1 y Value2 emisores deben notificar acerca tanto Value1 y Value2 cambio de propiedad.

  4. La vista debe volver a leer y revalidar ambos valores y borrar la marca defectuosa.

  5. No estoy seguro de si WPF lo hará si encuentra que el evento de notificación se ha levantado pero el valor en realidad no ha cambiado.