2009-08-26 13 views
36

Estamos entrando en MVVM en WPF.¿Debería MVVM ViewModel realizar una conversión/validación de tipo?

Hemos implementado nuestros ViewModels con propiedades 'fuertemente tipadas' (int, double? Etc.) a las que nos vinculamos en la vista.

La conversión de tipos funciona bien, principalmente, por lo que ingresar datos es bastante simple. Pero nos encontramos con problemas con la validación.

Si, por ejemplo, se ingresa un valor no numérico en un cuadro de texto vinculado a una propiedad numérica, la conversión falla, la propiedad nunca se establece, y nunca tenemos la oportunidad de proporcionar una opinión adecuada al usuario. Peor aún, la propiedad conserva su valor actual, lo que provoca una discrepancia entre lo que se muestra en la vista y lo que realmente está en ViewModel.

Todo esto se puede manejar con convertidores de valor, lo sé. Pero he visto varias opiniones en el sentido de que la conversión no debe ser la responsabilidad de la vista en absoluto. Lo que se ingresa en la vista son cadenas, y la conversión, validación, etc. debe ser la responsabilidad de ViewModel (según el argumento).

En caso afirmativo, deberíamos reescribir la mayoría de las propiedades de nuestros ViewModels en cadena, y proporcionar información de error a través de la interfaz IErrorInfo, por ejemplo. Seguramente sería más simple, más delgado XAML en la vista. Por otro lado, la conversión, la validación, etc. serán menos declarativas, explícitas y flexibles, desde el punto de vista del diseñador de vistas.

Nos parece que estos dos enfoques son fundamentalmente diferentes, por lo que antes de decidirnos, nos gustaría algunas opiniones SO informadas sobre el asunto.

Entonces, ¿deberían los ViewModels exponer una interfaz simplificada, 'basada en texto' a la vista y manejar la conversión internamente? ¿O deberían las propiedades de ViewModel exponer los tipos de datos reales, dejando esos quehaceres a la vista para manejarlos?

Actualización:

difícil elegir un ganador aquí, pero finalmente aterrizó en uno de ustedes que concluye más o menos como yo.

Específicamente, hemos decidido mantener las propiedades de ViewModel escritas. La razón principal de esto es la flexibilidad que nos brinda en el diseño de la vista y el poder de la conversión/formato declarativo explícito en XAML.

Me di cuenta de una suposición con usted que no estará de acuerdo con nosotros en esto, que el diseño de la vista es fijo y listo. Por lo tanto, no es necesario tomar decisiones sobre la conversión, el formato, etc. en la vista. Pero el nuestro es un proceso ágil, y no tenemos todos los detalles esenciales de la UI descubiertos de antemano.

De hecho, dejar los detalles de la interfaz de usuario elaborados en el camino deja espacio para la creatividad y, además, en mi opinión, incluso un diseño meticulosamente trabajado siempre terminará cambiando a lo largo del proceso de implementación.

El objetivo de todo esto es que, mientras que la aplicación de reglas de negocio ciertamente pertenece al ViewModel, nos parece que la simple conversión y el formateo es una cosa vista. Puede sonar como una herejía, pero en realidad no creo que la conversión de tipos en la vista requiera pruebas unitarias (siempre que compruebemos los convertidores de tipo reales).

En general, una gran discusión, amigos, con opiniones bien formuladas e informadas. Gracias.

+2

Estaba a punto de publicar esta pregunta. +1 – Gishu

Respuesta

13

Esta es una pregunta muy interesante y que no creo que tenga una respuesta definitiva, pero haré todo lo posible para expresar mis pensamientos.

Mirando el patrón MVVM como yo lo entiendo, el punto del modelo de vista es exponer los datos de una manera de la vista puede entender sin ninguna hipótesis sobre la forma en que la vista se va a usar. Por ejemplo vamos a suponer que estamos modelando la velocidad de un coche:

public class CarModel 
{ 
    public int MilesPerHour { get; set; } 
} 

public class CarViewModel 
{ 
    private CarModel _model; 

    public int MilesPerHour 
    { 
     get { return _model.MilesPerHour; } 
     set { _model.MilesPerHour = value; } 
    } 
} 

En el ejemplo anterior he expuesto la propiedad como un int ya que eso es lo que es en el modelo. Las desventajas de esto se han enumerado en su pregunta, pero la principal ventaja es que le da al creador de la vista una valiosa información sobre cómo mostrar esa información. Recuerde que nosotros (como autores de ViewModel) no sabemos a qué se parece la Vista. Al comprometerse con la idea de que los datos sean un int, View puede usar un cuadro de texto u otro control que solo acepte números (un dial, por ejemplo) para mostrar la información. Si decimos que vamos a formatear los datos de manera que suponer que es útil para la Vista, le quita esa importante potencia.

Por otro lado, trabajamos en el mundo real. Tendemos a saber cuál es la vista. Raramente podemos conectar y reproducir diferentes vistas sobre el mismo modelo de vista y agregar el código de conversión al ViewModel es simplemente más fácil. No creo que sea correcto, pero eso no significa que no encontrarás mi código de producción usándolo ...

Finalmente (y estoy seguro de que lo sabes, pero para completions ...) lógica de negocio debe hacerse en el ViewModel. Si decidimos que el auto no debe superar los 70 mph, entonces no es responsabilidad de la vista hacer cumplir eso. Por lo tanto, terminará con algún tipo de proveedor de errores, pero a nivel de empresa en lugar de a nivel de pantalla.


Vale, puede que finalmente no fue ....

yo quería hacer frente a los comentarios hechos por Kent, y mis pensamientos no encajan en un comentario.

Obviamente, la principal diferencia entre mi punto de vista y el de Kent (según tengo entendido) es que lee ViewModel para que sea un Modelo de la Vista y lo leo como lo que expone el Modelo a la Vista. Admitiré una sutil diferencia, pero creo que el resultado es que no quiero eliminar la información que proporciona el modelo, incluso si eso facilita la vista específica que estoy usando.

Mi punto de vista se basa en la suposición de que debe poder intercambiar puntos de vista, deben ser elementos fugaces que pueden cambiar según los requisitos de tamaño de pantalla, hardware, plataforma, latencia y entorno. El giro interesante es que tengo nunca realmente necesitaba esta funcionalidad, ni vi nada (más allá de las aplicaciones de prueba de concepto) que alguna vez la haya usado, pero si aceptamos que no la usaremos ahora o en cualquier punto en el futuro , y que cada ViewModel funcionará con una, y solo una, View, entonces también podemos volver a poner todo el código en el archivo de código subyacente y arrojar el ViewModel por completo; después de todo, está tan estrechamente acoplado que puede también ser la misma clase

Idealmente, me gustaría una situación en la que ViewModel pueda decir "este valor es una int, siempre será una int, y puede mostrarlo de todos modos que desee. Pero puede devolver algo a mí y a mí Haré todo lo posible para que se ajuste, y si no puedo, te lo haré saber ". Básicamente, mi propiedad MilesPerHour debería tener un int getter, pero un setter de objetos. De esta forma, las vistas conservan toda la información que considero que necesitan, pero no tienen que preocuparse por las conversiones o la validación.

+1

Muy bien puesto, Martin. Gracias. –

+0

Espero que sepas cómo es la vista.Si no, hay algo que se rompe seriamente con su colaboración entre desarrolladores y diseñadores. Asumir la responsabilidad de ciertos activos no implica que trabajemos en un vacío, aún necesitamos entender lo que el otro está haciendo. –

+0

No sé cómo se ve la vista si estoy trabajando en una aplicación que puede ser desprotegida por terceros. Pero incluso fuera de ese escenario, me refería al patrón MVVM que implica que, en un mundo ideal, ViewModel no debería saber nada sobre la Vista (incluso si es WPF, Webforms u otra cosa). –

5

Esta es una buena pregunta, y ciertamente puedo ver ambos lados de la discusión.

Mi idea es que lo que realmente está buscando es un NumericInputControl adecuado que pueda usar en su xaml. Esto proporcionará una mejor experiencia de usuario porque sus usuarios no podrán ingresar texto accidentalmente en un campo numérico y, debido a que el control restringe la entrada sin validarlo, puede mantener el modelo de vista con más caracteres.

No estoy seguro de cómo te gustaría implementar una, sé que los controles clásicos spinner/NumericUpDown están cayendo en desgracia porque no son compatibles con el tacto, pero no creo que la introducción de dicho control violará la pureza del enfoque de diseño o sus ViewModels. Recibirá un número que luego podrá validar en el rango apropiado, proporcionar comentarios a través del IDataErrorInfo como de costumbre, y así sucesivamente. :) Esta técnica te permite obtener lo mejor de ambos mundos sin ningún inconveniente real (excepto la creación de un control numérico).

+1

Hm. Está proponiendo una división del trabajo: la vista se convierte hacia y desde el tipo correcto, y el modelo de vista valida los datos convertidos. Eso tiene sentido. –

8

Absolutamente Pertenece en el modelo de vista, por todas las razones habituales, incluyendo:

  • diseñadores poseen el XAML. ¿Desea que los diseñadores tengan que comprender e implementar la lógica de conversión y validación del tipo de requisitos?
  • Testabilidad. ¿No quiere validar que su lógica de conversión y validación está funcionando correctamente? Es mucho más difícil si está incrustado en la vista.

Por otra parte, la conversión, validación, etc. habrá menos declarativa, explícita y flexible, desde el punto de vista del diseñador Ver

creo que este es un punto discutible, porque el diseñador de vistas debe ser responsable de estas cosas. El diseñador está tratando de hacer que la interfaz de usuario se vea y sienta de cierta manera; es el desarrollador quien implementa la lógica comercial, incluida la lógica de conversión y validación.

5

¿Debería MVVM ViewModel realizar el tipo de conversión ?

.

El modelo de vista es una capa de abstracción entre la vista y el modelo, el lugar perfecto para realizar conversiones de tipo (en lugar de voluminosos convertidores de valores). La validación debe ocurrir absolutamente como parte del modelo de vista.

Utilizamos nuestro Modelo de vista para manejar las conversiones tanto como sea posible para los tipos de datos. Esto reduce la necesidad de un convertidor de valor a algunas circunstancias muy específicas. Desea exponer cualquier tipo que sea más fácil de usar para la vista. Esto ha estado funcionando bien.

La una pregunta específica que planteó:

Si, por ejemplo, un valor no numérico se entró en un cuadro de texto dependiente de una propiedad numérica , la conversión falla, la propiedad está nunca se ponía y nunca tenemos la oportunidad de proporcionar comentarios adecuados para el usuario. Peor aún, la propiedad conserva su valor actual , lo que lleva a una discrepancia entre lo que se muestra en la vista y lo que está realmente en el modelo de vista.

, puede ser tratada mediante la exposición de su punto de vista el tipo de modelo como anulable tipo . Esto debería permitir que la fuente subyacente se actualice, incluso si se ingresan datos no válidos, y activar la validación. Esto funcionó en una situación similar que tuvimos con DateTime y un selector de fecha y hora.

Mantenga la vista como tonta. No tenemos diseñadores oficiales, nuestros desarrolladores son nuestros diseñadores, por lo que mantener la vista mudo tiene algunas ventajas:

  • Nosotros (los desarrolladores) se quedan con nuestra salud mental (XAML es algo menos detallado)
  • La lógica de negocio (incluida la validación) se mantiene en el modelo de vista y puede habilitar las pruebas

¡Buena suerte!

-Z

0

O deberían propiedades ViewModel exponer los tipos de datos reales, dejando esas tareas a la vista de manejar?

  1. Conversión y plantillas se hacen en View, porque ambos son sólo una conversión de values, models y viewmodels en controls! Controls están disponibles solo dentro de View.

  2. Validación se realiza en ViewModel, ya que la validación se realiza de acuerdo a las reglas de negocio e incluso puede hacerse a través de una llamada a un servicio remoto. La vista no sabe nada sobre las reglas de negocio, pero sabe cómo presentar los resultados de validación.

Si, por ejemplo, un valor no numérico se introduce en un cuadro de texto dependiente de una propiedad numérica

Un adecuadamente elaborado control de cuadro de texto numérico nunca permite al usuario introducir un no valor numérico.

Cuestiones relacionadas