Co to jest ViewModelLocator i jakie są jego zalety / wady w porównaniu do Datatematplates?

Czy ktoś może mi podać krótkie podsumowanie czym jest ViewModelLocator, jak działa i jakie są plusy/minusy używania go w porównaniu do Datatematplates?

Próbowałem znaleźć informacje w Google, ale wydaje się, że jest wiele różnych implementacji tego i nie ma listy striaght co to jest i plusy / minusy korzystania z niego.

Author: Jon, 2011-03-28

3 answers

Intro

W MVVM zwyczajową praktyką jest, aby widoki odnajdywały swoje Viewmodele, rozwiązując je z kontenera dependency injection (DI). Dzieje się to automatycznie, gdy kontener jest proszony o dostarczenie (rozwiązanie) instancji klasy View. Kontener wstrzykuje ViewModel do widoku przez wywołanie konstruktora widoku, który akceptuje parametr ViewModel; schemat ten nazywa się inversion of control (IoC).

Korzyści z DI

Główną korzyścią jest to, że kontener może być skonfigurowany w czasie wykonywania {[16] } z instrukcjami, jak rozwiązać typy, których od niego żądamy. Pozwala to na większą testowalność, nakazując jej rozwiązywanie typów (widoków i ViewModels), których używamy, gdy nasza aplikacja faktycznie działa, ale instruując ją inaczej podczas uruchamiania testów jednostkowych dla aplikacji. W tym drugim przypadku aplikacja nie będzie miała nawet interfejsu użytkownika (nie działa, tylko testy są), więc kontener rozwiąże mocks w miejsce "normalnych" typów używanych podczas uruchamiania aplikacji.

Problemy wynikające z DI

Do tej pory widzieliśmy, że podejście DI umożliwia łatwą testowalność aplikacji poprzez dodanie warstwy abstrakcji nad tworzeniem komponentów aplikacji. Jest jeden problem z tym podejściem: to nie gra dobrze z projektantami wizualnymi , takimi jak Microsoft Expression Blend.

Problem polega na tym, że w obu normalnych uruchamianie aplikacji i uruchamianie testów jednostkowych, ktoś musi skonfigurować kontener z instrukcjami, jakie typy należy rozwiązać; dodatkowo ktoś musi poprosić kontener o rozwiązanie widoków, aby można było wprowadzić do nich modele widoków.

Jednak w czasie projektowania nie ma naszego kodu działającego . Projektant próbuje użyć reflection do stworzenia instancji naszych poglądów, co oznacza, że:

  • jeśli Konstruktor widoku wymaga ViewModel przykład projektant w ogóle nie będzie w stanie utworzyć instancji widoku-będzie to błąd w kontrolowany sposób
  • jeśli Widok ma konstruktor bez parametru, Widok zostanie utworzony, ale jego DataContext będzie null, więc otrzymamy "pusty" widok w Projektancie - co nie jest zbyt użyteczne

Enter Viewmodellocator

ViewModelLocator jest dodatkową abstrakcją używaną w ten sposób:

  • sam widok tworzy instancję ViewModelLocator jako część z jego zasobów i databinduje swój DataContext do właściwości ViewModel lokalizatora
  • lokalizator jakoś wykrywa czy jesteśmy w trybie projektowym
  • jeśli nie jest w trybie projektowania, lokalizator zwraca model widoku, który rozwiązuje z kontenera DI, jak wyjaśniono powyżej
  • jeśli w trybie projektowania, lokalizator zwraca stały" atrapa " ViewModel przy użyciu własnej logiki (pamiętaj: nie ma kontenera w czasie projektowania!); ten ViewModel zazwyczaj jest prepopulowany z atrapa danych

Oczywiście oznacza to, że Widok musi mieć na początku bez parametru konstruktor (w przeciwnym razie projektant nie będzie w stanie utworzyć jego instancji).

Podsumowanie

Viewmodellocator to idiom, który pozwala zachować zalety DI W aplikacji MVVM, jednocześnie pozwalając twojemu kodowi dobrze bawić się z projektantami wizualnymi. Jest to czasami nazywane "mieszalnością" aplikacji (odnoszącą się do mieszanki wyrażeń).

Po przetrawieniu powyższego, zobacz praktyczny przykład tutaj .

Wreszcie, używanie szablonów danych nie jest alternatywą dla używania ViewModelLocator, ale alternatywą dla używania jawnych par View/ViewModel dla części interfejsu użytkownika. Często może się okazać, że nie ma potrzeby definiowania widoku dla modelu widoku, ponieważ można zamiast tego użyć szablonu danych.

 175
Author: Jon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-11-13 14:03:22

Przykładowa implementacja @Jon ' s answer

Mam klasę lokalizatora modelu widoku. Każda właściwość będzie instancją modelu widoku, który zamierzam przydzielić w moim widoku. Mogę sprawdzić, czy kod działa w trybie projektowania, czy nie używa DesignerProperties.GetIsInDesignMode. Pozwala mi to na wykorzystanie makiety modelu podczas projektowania i rzeczywistego obiektu podczas uruchamiania aplikacji.

public class ViewModelLocator
{
    private DependencyObject dummy = new DependencyObject();

    public IMainViewModel MainViewModel
    {
        get
        {
            if (IsInDesignMode())
            {
                return new MockMainViewModel();
            }

            return MyIoC.Container.GetExportedValue<IMainViewModel>();
        }
    }

    // returns true if editing .xaml file in VS for example
    private bool IsInDesignMode()
    {
        return DesignerProperties.GetIsInDesignMode(dummy);
    }
}

I aby z niego korzystać Mogę dodać mój lokalizator do zasobów App.xaml:

xmlns:core="clr-namespace:MyViewModelLocatorNamespace"

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

A następnie podłączyć twój widok (np. MainView.xaml) do twojego viewmodel:

<Window ...
  DataContext="{Binding Path=MainViewModel, Source={StaticResource ViewModelLocator}}">
 7
Author: BrunoLM,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 10:31:30

Nie rozumiem, dlaczego inne odpowiedzi na to pytanie owijają się wokół projektanta.

Celem lokalizatora modelu widoku jest umożliwienie tworzenia instancji tego widoku (tak, Lokalizator modelu widoku = Widok pierwszy):

public void MyWindowViewModel(IService someService)
{
}

Zamiast tylko tego:

public void MyWindowViewModel()
{
}

Deklarując to:

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

Gdzie ViewModelLocator jest klasą, która odwołuje się do IoC I w ten sposób rozwiązuje właściwość MainWindowModel, którą eksponuje.

Nie ma to nic wspólnego z dostarczaniem modeli widoku do widoku. Jeśli chcesz tego, po prostu zrób

d:DataContext="{d:DesignInstance MockViewModels:MockMainWindowModel, IsDesignTimeCreatable=True}"

Lokalizator modelu widoku jest owijką wokół pewnej (dowolnej) inwersji kontenera sterującego, na przykład Unity.

Zobacz:

 2
Author: Hristo Yankov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 10:31:29