2012-02-14 11 views
5

En mi aplicación WPF utilizo el patrón MVVM junto con la inyección de dependencia.Datos obsoletos en MVVM ViewModels con inyección de dependencia

Los ViewModels que preparan datos de la base de datos obtienen el repositorio inyectado en el constructor. También completan las propiedades con los datos del repositorio en el constructor.

Los ViewModels se crean todos en el constructor estático de la clase ViewModelLocator que todas las Vistas usan para vincular a su ViewModel.

Esto tiene las siguientes desventajas:

  1. Los datos de las vistas no se actualiza nunca, ni siquiera cuando se cierra y volver a abrirlos, porque la instancia modelo de vista es siempre la misma.
  2. Al abrir la primera vista, todos los Modelos de Vista se instancian y los datos que requieren se cargan de la base de datos.

me ocurren dos maneras de resolver estos problemas:

  1. Haga cada modelo de vista implementar un método que lee los datos de la base de datos e inicializa las propiedades - en lugar de hacerlo en el constructor. Esto requeriría llamar a ese método cada vez que se abra una vista. Esto introduce temporal coupling que no me gusta.
  2. Implemente el ViewModelLocator de tal forma que cree el modelo de vista solicitado cada vez que se llame a la propiedad correspondiente en ViewModelLocator. No me gusta este método, porque mi raíz de composición no se ejecutará al inicio del programa, sino que se extenderá durante toda la vida de la instancia del programa.

¿Hay alguna otra forma de resolver este problema? ¿Cómo están solucionando esto los demás?

Respuesta

2

implementar el ViewModelLocator de tal manera que se crea el modelo de vista solicitada cada vez que la propiedad correspondiente en la ViewModelLocator se llama.

Este es uno de los enfoques que generalmente tomo en situaciones como esta. Sin embargo, en lugar de tener el ViewModelLocator compuesto por DI de ViewModels, compongo fábricas que crean el ViewModel.

No me gusta este método, porque mi raíz de composición no se ejecutará al inicio del programa, sino que se extenderá durante toda la vida de la instancia del programa.

Esto se "resuelve", al menos parcialmente, haciendo que la composición componga fábricas en lugar de los propios tipos. La composición ocurre una vez al inicio, pero la creación puede ocurrir en cualquier momento del ViewModel en cuestión.

Por ejemplo, utilizando MEF, puede cambiar sus importaciones para utilizar ExportFactory<T> en lugar de su tipo directamente. Junto con NonShared Creation Policy, puede construir ViewModels, según sea necesario, y siempre trabajar con datos nuevos, sin los problemas de acoplamiento temporal.

+0

Gracias por su respuesta. Tener una fábrica para cada uno de mis modelos ViewModels parece ser un poco exagerado, ya que las fábricas solo se usarían en un lugar y no son necesarias actualmente. Además, no hacen nada más que 'container.Resolve '. Como ViewModelLocator aún sería el único lugar donde se usaría el contenedor, prefiero llamar 'container.Resolve' sobre las fábricas abstractas, porque incluso en este caso el contenedor no se filtraría en el código de la aplicación. La única ventaja de las fábricas abstractas que puedo pensar sería un error inmediato al inicio (cont.) –

+0

(cont.) Si la configuración del contenedor no fuera correcta. –

0

Mi clase base abstracta ViewModelBase requiere un método abstracto RefreshDataCore(). Este método se puede invocar manualmente llamando a Refresh() en la instancia de ViewModel o estableciendo un indicador IsDirty. Cuando ViewModel.IsVisible es verdadero y IsDirty se configura, también se llamará a Refresh().

De esta manera puede tener una actualización de datos perezosa cada vez que sus modelos de vista se vuelvan visibles y también puede invocar manualmente una actualización llamando a Refresh().

Ejemplo a continuación. (Me queda notificaciones INPC a cabo por simplicidad)

public abstract class ViewModelBase 
{ 
    //Pull your data from the repository here 
    protected abstract void RefreshCore(); 
    public void Refresh() 
    { 
      RefreshCore(); 
      IsDirty = false; 
    } 

    private bool _isVisible = false; 
    //DataBind this to the visibility of element "hosting" your view model 
    public bool IsVisible 
    { 
     get { return _isVisible; } 
     set 
     { 
       if (_isVisible == value) 
        return; 


       _isVisible = value; 
       if (IsVisible && IsDirty) 
        Refresh(); 
     } 
    } 

    private bool _isDirty = true; 
    public bool IsDirty 
    { 
     get { return _isDirty; } 
     set 
     { 
      if (_isDirty == value) 
       return; 

      _isDirty = value; 
      if (IsVisible && IsDirty) 
       Refresh(); 
     } 
    } 

} 
+1

¿Cómo resuelves el problema del acoplamiento temporal? ¿Simplemente vives con eso y siempre llamas a refresh cuando sea necesario? –

+0

Tengo un ApplicationViewModel que comprueba periódicamente el estado de los datos y establece los indicadores IsDirty apropiados (pero solo los modelos de vista visible se actualizarán activamente) Por razones de rendimiento, ApplicationViewModel también contiene el caché local de datos que las otras instancias de ViewModelBase leer en sus métodos RefreshDataCore(). Tiene total flexibilidad para implementar esto como lo necesite aunque – cordialgerm

+0

Gracias por su respuesta. Sin embargo, no veo el acoplamiento temporal resuelto, así que no es lo que voy a usar. –

Cuestiones relacionadas