ViewModels en ViewModelLocator MVVM Light

¿Es correcto almacenar todos mis ViewModels en SimpleIoc? Por ejemplo, tengo tres páginas MainPage, Photos, Directories (por lo tanto, tres ViewModels -> MainVM, PhotosVM, DirectoriesVM). ¿Debo configurar DataContext en cada página para ver la propiedad del modelo en ViewModelLocator o anidar ViewModels como propiedades en MainVM y vincular cada página DataContext a Main.PhotosVMProperty, Main.DirectoriesVMProperty, etc.? ¿Alguien podría explicarme la idea y el propósito de IoC?

Primero, veamos qué hace ViewModelLocator y por qué lo usamos:

ViewModelLocator se declara como un objeto en nuestra página App.xaml y es una aplicación singleton. Vamos a tener uno, y solo uno de ellos estará disponible para la aplicación cuando se ejecute.

ViewModelLocator es la fuente de todos nuestros ViewModels en MVVM Light. Para cada ViewModel, tendremos una propiedad en ViewModelLocator que nos permitirá obtener un ViewModel para una Vista. Este código se ve así:

public class ViewModelLocator { public MainPageViewModel MainPage { get { return new MainPageViewModel(); } } } 

Esta es una parte de mi App.xaml:

    

Esta es una pieza de View.xaml

 DataContext="{Binding MainPage, Source={StaticResource ViewModelLocator}}" 

Hasta aquí todo bien. Para responder a su primera pregunta, ¿tiene que usar Ioc en MVVM Light? No. No es necesario, ya que su viewmodel se otorgará a su vista completamente creada e instanciada por ViewModelLocator.

Ahora, a su segunda pregunta: ¿Cuál es el propósito de IoC?

IoC está diseñado para permitirte hacer lo siguiente:

Con Mvvm Light haces lo anterior así:

 public class ViewModelLocator { public ViewModelLocator() { ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default); if (ViewModelBase.IsInDesignModeStatic) { SimpleIoc.Default.Register(); } else { SimpleIoc.Default.Register(); } SimpleIoc.Default.Register(); } public MainViewModel Main { get { return SimpleIoc.Default.GetInstance(); } } } public class MainViewModel { public ObservableCollection Foos { get; set; } public MainViewModel(IDataService dataService) { _dataService=dataService; Foos=_dataService.GetFoos(); } } 

Cuando resuelvo mi MainViewModel cuando llamo

 SimpleIoc.Default.GetInstance() 

lo que ocurre internamente es que SimpleIoc comprueba si el MainViewModel tiene alguna dependencia (parámetros en su constructor). A continuación, intenta resolver estos parámetros mirando las interfaces que se han registrado con él. Lo hace de forma recursiva, por lo que si DataService tiene una dependencia, se creará una instancia y se pasará al constructor de DataService cuando también se esté creando una instancia.

¿Por qué haría todo este trabajo?

  1. Haga que sus clases sean fácilmente comprobables por unidad
  2. Haga que su código sea impulsado por la interfaz. Esto significa que está haciendo referencia a interfaces en lugar de clases concretas
  3. Haga su código débilmente acoplado. Esto significa que alguien puede cambiar la implementación de una interfaz y las clases que consumen esa interfaz no se preocupan y no tienen que volver a codificarse.
  4. Resuelva sus dependencias de clases de forma automática.
  5. En MVVM Light, verá que puede decir cuándo se está ejecutando en modo de diseño ( ViewModelBase.IsInDesignModeStatic ), esto significa que puede crear servicios en tiempo de diseño para proporcionar los datos de su viewmodels para que su vista en Visual Studio contenga datos reales.

MVVM Light tiene muchas características agradables, pero me parece que Service Locator crea una dependencia no deseada de las vistas en los modelos de visualización. Idealmente, me gustaría tener el ViewModelLocator en la Biblioteca A, los modelos de vista en la Biblioteca B y las vistas en la Biblioteca C. Luego puedo mezclarlos y combinarlos según sea necesario para proyectos futuros. Sin embargo, en el diseño de MVVM Light, hasta donde puedo ver, las vistas (Biblioteca C) siempre tendrán una dependencia en ViewModelLocator (esto está bien) pero debido a que ViewModelLocator (Biblioteca A) siempre tendrá una dependencia en el ver modelos (Biblioteca B), las vistas siempre dependerán de los modelos de vista (esto no está bien porque una vista ahora debe incluir todas las bibliotecas de modelos de vista con las que se haya utilizado en todos los productos).

Creo que Prism evita este problema usando claves de cadena de alguna manera. ¿Me estoy perdiendo de algo?

Oops! Creo que acabo de responder mi propia pregunta. La solución es hacer que la Biblioteca A, el ServiceLocator, sea específica para una solución particular (producto). A continuación, contiene una referencia a los modelos de vista solo para esa solución. Entonces las vistas dependen de este ServiceLocator, que a su vez depende de todos los modelos de vista para ese producto. El resultado final es que las vistas dependen solo de los modelos de vistas con los que se usará para ese producto. No hay problema con el hecho de que estamos duplicando el ServiceLocator para cada solución porque este módulo contiene solo código que es específico para la solución. Los componentes del ServiceLocator como la clase SimpleIoc son, por supuesto, comunes a todas las soluciones, pero se han tenido en cuenta en las clases reutilizables que invocamos en ServiceLocator.

Para resumir las cosas, el problema que trato de resolver es suponer que una solución tiene 6 modelos de vista, cuatro de los cuales están estrechamente relacionados y dos de ellos están estrechamente relacionados. Por lo tanto, creamos dos conjuntos, cada uno con los modelos de vista estrechamente relacionados. Supongamos que diseñamos un producto que utiliza un conjunto de modelos de vista y que la solución está diseñada para ejecutar Windows 8. Ahora las vistas son todas diferentes y queremos reutilizar solo un conjunto (conjunto) de modelos de vista. Así que simplemente creamos un nuevo ensamblado ServiceLocator que apunta a este ensamblaje de modelos de vista y también a cualquier otro que necesitemos. Nuestras nuevas vistas de Windows 8 ahora dependen de este nuevo ensamblado de ServiceLocator y solo de los modelos de vista que se usan en nuestro nuevo producto (solución).