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.
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ędzienull
, 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.
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}}">
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:
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