2010-03-29 19 views
12

Estoy usando MVVM en una aplicación WPF. Soy muy nuevo para ambos. Permítanme decir que no soy el más puro en el patrón de MVVM, estoy tratando de utilizar todas las mejores prácticas posibles, pero estoy tratando de hacer lo que creo que son compromisos razonables para que funcione en nuestro entorno. Por ejemplo, no estoy tratando de lograr el 0% de código en mi código de vista detrás.MVVM Ver referencia a ViewModel

Tengo un par de preguntas sobre las mejores prácticas.

1) Entiendo que no quiero que mi VM sepa sobre la Vista adjunta, pero ¿es razonable que la Vista tenga una referencia a su VM?

2) Si un control en una Vista abre otra Vista (como un cuadro de diálogo), ¿debo manejar esto en la Vista? Parece incorrecto manejarlo en la VM, ya que la VM tiene algún conocimiento de una Vista específica.

+0

Una vista hace referencia a una máquina virtual, pero no debería ser de otra manera. http://stackoverflow.com/a/3670669/1977871 – VivekDev

Respuesta

10

1) La Vista definitivamente tiene una referencia al ViewModel a través del DataContext. Y se le permite emitir el DataContext en su Vista:

public class ShellView : Window 
{ 
    … 
    public ShellViewModel { get { return DataContext as ShellViewModel; } } 

Ésta no es una violación con el patrón Model-View-ViewModel.

.

2) Tienes razón. Un ViewModel no debe abrir otra Vista. Un mejor enfoque es usar Controladores. Ellos son responsables del flujo de trabajo de una aplicación.

Si está interesado en información más detallada, entonces puede echar un vistazo a WPF Application Framework (WAF).

+0

+1 Para expandir un poco la explicación de jbe para # 2, puede exponer un comando en la VM que está conectado al controlador de comando de un controlador que controlará la visualización de la segunda vista. Además de WAF, también puede consultar la Biblioteca de aplicaciones compuestas del equipo de P & P (también conocido como Prism): http://compositewpf.codeplex.com/Wikipage –

+0

Sí, está claro que la Vista sabe acerca de la VM a través del DataContext, supongo que simplemente no había visto eso ya que todo el enlace de datos en mi xaml es tan dependiente de la máquina virtual que tener una referencia más fuerte en mi código de vistas apenas parece algo malo. Y gracias por la sugerencia de los controladores, investigaré ese patrón. – BrettRobi

+0

'modelo público de ShellViewModel {get {return DataContext como ShellViewModel; }} ' –

2

1). La vista necesitará una referencia al modelo de vista en algún nivel, ya que el modelo de vista actuará como el contexto de datos de la vista.

2) Una manera de manejar esto es tener un modelo de vista generalizado que representa un cuadro de diálogo, que es propiedad del modelo de vista principal (el que está siendo utilizado como las vistas DataContext.)

Se puede utilizar un comando para cajón una nueva instancia de un modelo de vista de diálogo, que tendrá una plantilla de datos correspondiente definida en sus recursos. Esta plantilla se establecerá para vincularse al tipo de modelo de vista de diálogo.

+0

+1 pero creo que para el punto 1), el OP pregunta si está bien que la clase View conozca la clase exacta de ViewModel, en lugar de solo enlazar un contexto de datos de tipo desconocido a través de nombres de propiedad. –

+0

Por Wim, de hecho, me refería a que la clase View tiene una referencia al ViewModel, no solo a través de databinding (que es abstracto). – BrettRobi

+0

En el punto n. ° 2. Estoy usando el juego de herramientas MVVM Light en el que creo Vistas, que luego se unen a un ViewModel a través de un servicio de Localizador. Así que no estoy creando máquinas virtuales, ya que no saben cómo adjuntar una vista a sí mismos. Por lo tanto, parece que necesito una forma de crear el cuadro de diálogo Ver y ¿dónde debería suceder eso (Vista o máquina virtual)? – BrettRobi

3

1) Aquí hay dos prácticas simples para que View "conozca" un ViewModel. Es razonable que una Vista conozca un ViewModel (para enlace de datos), pero es posible que no lo necesite en su caso. Vea si alguno de estos enfoques ayuda a resolver su problema. Hay otras maneras, pero éstos deben ser lo suficientemente simple:

public View(ViewModel vm) 
{ 
    View.DataContext = vm; 
} 

public Bootstrapper(View v, ViewModel vm) 
{ 
    v.DataContext = vm; 
    //or, if you want it to have no parameters 
    View v = new View(); 
    ViewModel vm = new ViewModel(); 
    v.DataContext = vm; 
} 

La primera opción no es malo si usted tiene una herramienta de ubicación de servicio, pero hay un sabor de MVVM que no le gusta ningún código en el Ver código detrás. La segunda opción tampoco está mal, debería ser lo suficientemente simple para su tarea.

2.) Esta pregunta puede ser un poco difícil en el diseño de MVVM. Si estamos hablando de un Win32 MessageBox general, a menudo separaré esa lógica en un objeto adicional y lo colocaré en la máquina virtual. De esta manera tiende a ser un poco más claro. (Por ejemplo, he seleccionado un elemento en un ListBox, he adjuntado un Delete ICommand a esa acción, y en mi ViewModel cuando este ICommand se ejecuta, pincharé mi MessageBoxObject para preguntar si el usuario "quiere realmente eliminar" esto ít). Los "Diálogos" más avanzados utilizarían ViewModels y DataTemplates adicionales para esos ViewModels. Prefiero el enfoque Mediator.

+0

Gracias, se agradece la retroalimentación – BrettRobi

1

Build Your Own MVVM Framework

me encontré con el enfoque sugerido por Rob Eisenberg muy interesante.

puntos clave:

Convención
  1. sobre la configuración
  2. ViewModel primera

que es muy similar a la filosofía ASP.NET MVC.

Recomiendo mucho ver el video.

2

Bastante tarde, pero creo que esto es lo suficientemente complicado como para merecer muchas perspectivas diferentes.


entiendo que no quiero que mi máquina virtual para saber acerca de la vista conectada, pero es razonable para la vista para tener una referencia a su máquina virtual?

Como ya se ha respondido, una disposición correcta de View-ViewModel implica que ViewModel se asigne como la propiedad DataContext de View. Eso permite que los DataBindings se establezcan "automágicamente" a partir de XAML declarativo, o que se ajusten a través del código subyacente.

A veces, usted estará tentado a escribir, en su código detrás, algo como esto:

var dc = DataContext as CleverViewModel; 
CleverViewModel.CleverProperty.Add(someValue); // just a simple example 

Creo que la manera adecuada para lograr este tipo de cosas es que no se ponga DataContext, pero en su lugar:

  1. tener cierto control dedicado en Ver, por ejemplo, un ItemsControl con su ItemsSource de dos vías de enlace de datos a alguna propiedad en modelo de vista:

    <ItemsSource x:Name="cleverControl" Visibility="Collapsed" ItemsSource="{Binding CleverProperty, Mode=TwoWay}"/>

  2. moldeada la propiedad con destino en lugar de todo el modelo de vista, en el código detrás:

    var collection = (ObservableCollection<double>)cleverControl.ItemsSource; collection.Add(someValue);

Nota la diferencia importante: el segundo enfoque en este ejemplo no requiere la Ver para conocer el tipo de ViewModel, solo necesita una propiedad llamada CleverProperty de tipo ObservableCollection<double>. Esto me permite tener ViewModels polimórficos o incluso pato-tipados.


Si un control en una vista se abre otra vista (por ejemplo, un cuadro de diálogo) debería manejar esto en la vista? Parece incorrecto manejarlo en la máquina virtual desde , luego la máquina virtual tiene algún conocimiento de una vista específica.

Esto no debería ocurrir en MVVM estricto, y no es difícil evitar el uso de DataTemplates.DataTemplates mapa un determinado tipo de DataContext a un determinado tipo de vista, por lo que cada vez que el DataContext de ContentControl cambios, la pantalla también cambia, siempre y cuando tenga un DataTemplate para ese tipo:

  1. Un control en la vista podría enviar un comando al ViewModel, que a su vez actualizaría algunas de sus propias propiedades, que se reflejarían en la vista.

  2. Una vista podría contener otra vista, fuera del conocimiento de ViewModel. En este caso, el código subyacente puede manipular el contexto de datos de la vista contenida.

Hay más sutilezas, pero he estado utilizando este enfoque con buenos resultados. Espero que esto ayude a alguien.

Cuestiones relacionadas