2009-06-17 10 views
17

Digamos que tengo una vista que está vinculada a ViewModel A que tiene una colección observable Clientes.¿Cómo se pueden usar los convertidores WPF en un patrón MVVM?

Una ventaja de este patrón MVVM es que también puedo vincular la Vista a ViewModel B que lo llena de datos diferentes.

Pero, ¿y si en mi Ver convertidores de conversión para mostrar a mis clientes, p. Tengo un "ContractToCustomerConverter" que acepta un Contrato y devuelve el Cliente adecuado para que se muestre.

El problema es que el convertidor existe fuera del patrón MVVM y, por lo tanto, no sabe que mi ViewModel tiene otra fuente para los clientes.

  • hay una manera para la Ver para pasar el modelo de vista en el convertidor para que participe en el desacoplamiento de que el patrón MVVM ofrece?
  • ¿Hay alguna forma de que de alguna manera incluya el convertidor en mi ViewModel para que el convertidor use las dependencias actuales que ViewModel tiene disponible?
  • o son convertidores simplemente glorified code-behind y por lo tanto no se utiliza en el patrón MVVM, por lo que si está utilizando MVVM entonces simplemente crea sus propios "convertidores" (métodos en su clase ViewModel) que devuelven cosas como objetos de imagen , Objetos de Visibilidad, FlowDocuments, etc. para ser usados ​​en la vista, en lugar de usar conversores en absoluto?

(me encontré con estas preguntas después de ver el uso de convertidores en la aplicación de demostración de WPF que viene con el MVVM Template Toolkit download, consulte la "Muestra Messenger" después de desempaquetarlo.)

Respuesta

8

convertidores deben rara vez será usado con MVVM. De hecho, me esfuerzo por no usarlos en absoluto. La VM debe hacer todo lo que la vista necesita para hacer su trabajo. Si la vista necesita un Customer basado en un Contract, debe haber una propiedad Customer en la máquina virtual que se actualiza por la lógica de la VM cada vez que cambia el Contract.

Una ventaja de este patrón MVVM es que también puedo vincular la Vista al ViewModel B que lo llena de datos diferentes.

No estoy de acuerdo. En mi experiencia, las vistas no se comparten entre diferentes tipos de VM, y tampoco es un objetivo de MVVM.

+3

OK Veo que su punto acerca de las vistas no debe compartirse entre diferentes máquinas virtuales, pero un ViewModel debe poder ser compartido por diferentes vistas, de ahí la ventaja de la capacidad de prueba de MVVM, ¿no? Debería poder conectar una vista simulada y un modelo simulado a ViewModel para asegurarse de que todas las combinaciones de datos que recibe del modelo simulado producen los valores de propiedad correctos que quedan expuestos a la vista. ¿Estarías de acuerdo? –

12

Por lo general, no utilizo convertidores en absoluto en MVVM, a excepción de tareas de UI puras (como BooleanToVisibilityConverter, por ejemplo). En mi humilde opinión se debe más bien declarar una propiedad del cliente de tipo CustomerViewModel en su ContractViewModel, en lugar de utilizar un ContractToCustomerConverter

11

En this conversation hay un comentario que está de acuerdo con la posición de Kent, a no utilizar convertidores en absoluto, interesante:

Un ViewModel es básicamente un convertidor de valor con esteroides.Toma los datos "en bruto" y los convierte en algo amigable para la presentación, y viceversa. Si alguna vez se encuentra vinculando la propiedad de un elemento a la propiedad de ViewModel, y está utilizando un convertidor de valor, ¡deténgase! ¿Por qué no simplemente crear una propiedad en el ViewModel que expone los datos "formateados", y luego descartar el convertidor de valor?

Y en this conversation:

El único lugar donde puedo ver un uso para convertidores de valores en una arquitectura MVVM es elemento transversal enlaces. Si estoy vinculando el Visibilidad de un panel al IsChecked de un CheckBox, entonces necesitaré usar BooleanToVisibilityConverter.

5

Para aquellos que efectivamente dicen que no hay "convertidores no triviales" en la vista, ¿cómo se maneja lo siguiente?

Digamos que tengo un Modelo de sensores de clima que representa series de tiempo de lecturas de varios instrumentos (barómetro, higrómetro, termómetro, etc.) en una ubicación determinada.

Digamos que mi modelo de vista expone una colección observable de los sensores de mi modelo.

Tengo una vista que contiene un WPF Toolkit DataGrid que se une al modelo de vista con la propiedad ItemsSource establecida en una colección observable de sensores. ¿Cómo represento la vista de cada instrumento para un sensor dado? Al mostrar un pequeño gráfico (que Edward Tufte sparkline aquí) que se genera mediante la conversión de las series de tiempo a una fuente de imagen utilizando un convertidor (TimeSeriesToSparklineConverter)

Así es como pienso en MVVM: expone el modelo de datos para ver modelos. El modelo de vista expone el comportamiento, los datos del modelo y el estado a la vista. Las vistas hacen el trabajo de representar visualmente los datos del modelo y proporcionan una interfaz para los comportamientos consistentes con el estado del modelo de visualización.

Por lo tanto, no creo que las imágenes del sparkline entren en el Modelo (el Modelo es información, no una representación visual particular de la misma). Tampoco creo que las imágenes de sparkline vayan en el modelo de vista (¿y si mi vista quiere representar los datos de manera diferente, por ejemplo, como una fila de cuadrícula que solo muestra min, max, average, desviación estándar, etc. de la serie?). Por lo tanto, me parece que la Vista debe manejar el trabajo de transformar los datos en la representación deseada.

Así que si quiero exponer los comportamientos, los datos del modelo y el estado dado para un determinado modelo de vista en una interfaz de línea de comandos en lugar de una GUI de WPF, no quiero que mi modelo o mi modelo de visualización contengan imágenes. ¿Esto esta mal? ¿Vamos a tener un SensorCollectionGUIViewModel y un SensorCollectionCommandLineViewModel? Eso me parece incorrecto: pienso en el Modelo de Vista como una representación abstracta de la vista, no concreta y ligada a una tecnología particular como sugieren estos nombres.

Ahí es donde estoy en mi comprensión en constante evolución de MVVM. Entonces, para aquellos que dicen no usar convertidores, ¿qué hacen aquí?

+3

Veo el problema que describe así: Con un convertidor de valor, haría un ClimateSensorToSparklineGraphConverter que toma una colección de sensores de clima y genera una imagen. Para algo como crear una imagen de mapa de bits, no vas a estar haciendo esto con un DataTemplate y una colección de ViewModels que contienen ViewModels, en algún momento necesitas el código C# para crear la imagen. El problema viene cuando en el convertidor también accede, p. una colección de usuarios para determinar qué puede ver el usuario actual. Esto rompería MVVM ya que ViewModel debería tener a los usuarios inyectados. –

0

Agregaré mis 2 centavos a esta discusión.

Uso conversores, donde tiene sentido.

Explicación: Hay casos en los que necesita representar 1 valor en el Modelo de más formas en la interfaz de usuario. Expongo este valor a través de 1 tipo. El otro tipo es manejado a través del convertidor. Si tuviera que exponer 1 valor a través de 2 propiedades en VM, tendría que manejar manualmente las notificaciones de actualización.

Por ejemplo, tengo un modelo con 2 entradas: TotalCount, DoneCount. Ahora quiero que ambos valores se muestren en TextBlocks y, además, quiero mostrar el porcentaje realizado.

Resuelvo esto usando el convertidor múltiple DivisionConverter que toma 2 entradas previamente mencionadas.

Si tuviera que tener PercentDone especial en VM, tendría que actualizar esta propiedad siempre que se actualice DoneCount.

+0

Básicamente actualiza la propiedad PercentDone declarando el convertidor y haciendo que se dispare cuando su enlace arroja un propertychanged, solo que está representado por una clase con una función, en lugar de una propiedad ... Así que no creo que esto sea un real buen caso de uso. Creo que las cosas puras de UI a UI garantizan convertidores. – Joris