webentwicklung-frage-antwort-db.com.de

ViewModels in ViewModelLocator MVVM Light

Ist es richtig, alle meine ViewModels in SimpleIoc zu speichern? Zum Beispiel habe ich drei Seiten MainPage, Photos, Directories (daher drei ViewModels -> MainVM, PhotosVM, DirectoriesVM). Soll ich DataContext auf jeder Seite so einstellen, dass die Modelleigenschaften in ViewModelLocator angezeigt werden, oder ViewModels als Eigenschaften in MainVM verschachteln und die einzelnen Seiten DataContext an Main.PhotosVMProperty, Main.DirectoriesVMProperty usw. binden? Kann mir jemand Idee und Zweck von IoC erklären?

33
fex

Schauen wir uns zunächst an, was ViewModelLocator macht und warum wir es verwenden:

ViewModelLocator ist als Objekt auf unserer App.xaml-Seite deklariert und ein Anwendungs-Singleton. Wir haben eine und nur eine davon für die Anwendung verfügbar, wenn sie ausgeführt wird.

ViewModelLocator ist die Quelle für alle unsere ViewModels in MVVM Light. Für jedes ViewModel verfügen wir über eine Eigenschaft im ViewModelLocator, mit der wir ein ViewModel für eine View abrufen können. Dieser Code sieht folgendermaßen aus:

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

Dies ist ein Teil meiner App.xaml:

<Application.Resources>
    <vm:ViewModelLocator
        x:Key="ViewModelLocator" />
</Application.Resources>

Dies ist ein Stück aus View.xaml

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

So weit, ist es gut. Müssen Sie Ioc in MVVM Light verwenden, um Ihre erste Frage zu beantworten? Nein. Es ist nicht erforderlich, da Ihr Ansichtsmodell Ihrer Ansicht zugewiesen wird, die vollständig vom ViewModelLocator erstellt und instanziiert wurde.

Nun zu Ihrer zweiten Frage: Was ist der Zweck von IoC?

Mit IoC können Sie Folgendes tun:

Mit Mvvm Light machen Sie das Folgende:

public class ViewModelLocator
{
    public ViewModelLocator()
    {
        ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);

        if (ViewModelBase.IsInDesignModeStatic)
        {
            SimpleIoc.Default.Register<IDataService, Design.DesignDataService>();
        }
        else
        {
            SimpleIoc.Default.Register<IDataService, DataService>();         
        }

        SimpleIoc.Default.Register<MainViewModel>();
    }

    public MainViewModel Main
    {
        get { return SimpleIoc.Default.GetInstance<MainViewModel>(); }
    }
}

public class MainViewModel
{
    public ObservableCollection<Foo> Foos { get; set; }

    public MainViewModel(IDataService dataService)
    {
        _dataService=dataService;
        Foos=_dataService.GetFoos();
    }
}

Wenn ich mein MainViewModel auflöse, wenn ich anrufe

SimpleIoc.Default.GetInstance<MainViewModel>()

intern prüft SimpleIoc, ob das MainViewModel Abhängigkeiten aufweist (Parameter in seinem Konstruktor). Anschließend versucht es, diese Parameter aufzulösen, indem es sich die bei ihm registrierten Schnittstellen ansieht. Dies geschieht rekursiv. Wenn DataService eine Abhängigkeit hätte, würde er instanziiert und an den DataService-Konstruktor übergeben, wenn er ebenfalls instanziiert wird.

Warum sollte ich all diese Arbeit machen?

  1. Machen Sie Ihre Klassen einfach testbar
  2. Machen Sie Ihren Code schnittstellenorientiert. Dies bedeutet, dass Sie nicht auf konkrete Klassen, sondern auf Schnittstellen verweisen
  3. Machen Sie Ihren Code lose gekoppelt. Dies bedeutet, dass jemand die Implementierung einer Schnittstelle und von Klassen ändern kann, die diese Schnittstelle verbrauchen, es ist ihm egal und er muss nicht neu codiert werden.
  4. Lösen Sie Ihre Klassenabhängigkeiten automatisiert auf.
  5. In MVVM Light sehen Sie, dass es erkennen kann, wann es im Entwurfsmodus ausgeführt wird (ViewModelBase.IsInDesignModeStatic) bedeutet dies, dass Sie Entwurfszeitdienste erstellen können, um Ihre Ansichtsmodelldaten bereitzustellen, sodass Ihre Ansicht in Visual Studio tatsächliche Daten enthält.
124

MVVM Light hat viele nette Funktionen, aber es scheint mir, dass der Service Locator eine unerwünschte Abhängigkeit der Ansichten von den Ansichtsmodellen erzeugt. Idealerweise möchte ich den ViewModelLocator in Bibliothek A, die Ansichtsmodelle in Bibliothek B und die Ansichten in Bibliothek C haben. Dann kann ich diese nach Bedarf für zukünftige Projekte mischen und anpassen. Bei der Entwicklung von MVVM Light sind die Ansichten (Bibliothek C) meines Erachtens immer vom ViewModelLocator abhängig (dies ist in Ordnung), aber der ViewModelLocator (Bibliothek A) hat immer eine Abhängigkeit vom Ansichtsmodelle (Bibliothek B), dann hängen die Ansichten immer von den Ansichtsmodellen ab (dies ist nicht in Ordnung, da eine Ansicht jetzt alle Ansichtsmodellbibliotheken enthalten muss, mit denen sie jemals in allen Produkten verwendet wurde).

Ich glaube, dass Prism dieses Problem umgeht, indem es irgendwie String-Schlüssel verwendet. Vermisse ich etwas?

Hoppla! Ich glaube, ich habe gerade meine eigene Frage beantwortet. Die Lösung besteht darin, Bibliothek A, den ServiceLocator, für eine bestimmte Lösung (Produkt) spezifisch zu machen. Es enthält dann einen Verweis auf die Ansichtsmodelle nur für diese Lösung. Die Ansichten hängen dann von diesem ServiceLocator ab, der wiederum von allen Ansichtsmodellen für dieses Produkt abhängt. Das Endergebnis ist, dass die Ansichten nur von den Ansichtsmodellen abhängen, mit denen sie für dieses Produkt verwendet werden. Es gibt kein Problem damit, dass wir den ServiceLocator für jede Lösung duplizieren, da dieses Modul nur Code enthält, der für die Lösung spezifisch ist. Die Komponenten des ServiceLocators wie die SimpleIoc-Klasse sind natürlich allen Lösungen gemeinsam, aber diese wurden in wiederverwendbare Klassen zerlegt, die wir in ServiceLocator aufrufen.

Um die Dinge zusammenzufassen, das Problem, das ich zu lösen versuche, ist die Annahme, dass eine Lösung 6 Ansichtsmodelle hat, von denen vier eng miteinander verbunden sind und zwei eng miteinander verbunden sind. Wir erstellen daher zwei Baugruppen, die jeweils die eng verwandten Ansichtsmodelle enthalten. Angenommen, wir entwerfen ein Produkt, das einen Satz von Ansichtsmodellen verwendet, und die Lösung ist für Windows 8 ausgelegt. Jetzt sind alle Ansichten unterschiedlich, und wir möchten nur einen Satz (Assembly) von Ansichtsmodellen wiederverwenden. Daher erstellen wir nur eine neue ServiceLocator-Assembly, die auf diese Assembly von Ansichtsmodellen und auch auf alle anderen, die wir benötigen, verweist. Unsere neuen Windows 8-Ansichten hängen jetzt von dieser neuen ServiceLocator-Assembly und nur von den Ansichtsmodellen ab, die in unserem neuen Produkt (Lösung) verwendet werden.

1
Richard