MVVMLight ViewModelLocator регистрирующий сервис данных - PullRequest
7 голосов
/ 29 января 2012

Этот вопрос может показаться наивным, но я не смог понять этот код в файле ViewModelLocator.cs:

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

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

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

Я вижу, что мы используем DataService для получения данных (например, из службы WCF) и присвоения их MainViewModel. Но что, если я регистрирую более одной ViewModel? как это:

static ViewModelLocator()
{
    ....
    SimpleIoc.Default.Register<MainViewModel>();
    SimpleIoc.Default.Register<Page2ViewModel>();
}

и скажем, у меня есть другой DataService (например, DataService2), но этот я буду использовать с Page2ViewModel. как я могу это сделать?

Кроме того, если кто-то может помочь мне (или даже дать мне ссылку для чтения) по поводу приведенного выше кода. Понятия не имею, что это значит.

1 Ответ

21 голосов
/ 29 января 2012

Вы не назначаете IDataService для MainViewModel здесь. Вы регистрируете сопоставление типов, поэтому ваш контейнер будет знать, что он должен возвращать DataService всякий раз, когда требуется IDataService.

Это связано с внедрением зависимости http://en.wikipedia.org/wiki/Dependency_injection

Контейнер DI auto-wire зависимости, поэтому, когда вам нужен определенный тип, вы можете позвонить

ServiceLocator.Current.GetInstance<IDataService>()

или

ServiceLocator.Current.GetInstance<MainViewModel>()

и т.д.. Если он может построить его (чтобы вы зарегистрировали свои типы), он разрешит для вас полный граф зависимостей.

Например, если ваш MainViewModel имеет зависимость конструктора от IDataService, и вы не находитесь в режиме разработки, DataService будет введен в конструктор MainViewModel. Не бойтесь вводить модное слово , это просто вызов конструктора MainViewModel с соответствующими параметрами:).

Итак, MainViewModel не будет мешать Page2ViewModel здесь.

Я сделал для вас простой пример, чтобы продемонстрировать, что происходит (я использовал Unity, http://unity.codeplex.com/, но синтаксис почти такой же):

class Program
{
    static void Main(string[] args)
    {
        var container = new UnityContainer();
        container.RegisterType<IService, Service1>();
        container.RegisterType<IService, Service2>("MySpecificService");
        container.RegisterType<IRepository, Repository>();
        ServiceLocator.SetLocatorProvider(() => new UnityServiceLocator(container));

        var viewModel = ServiceLocator.Current.GetInstance<MainViewModel>();
        viewModel.Foo();
    }
}

interface IService
{
}

interface IRepository
{   
}

class Service1 : IService
{
    public Service1(IRepository repository)
    {
        Console.WriteLine("Service1 created");
    }
}

class Service2 : IService
{
    public Service2()
    {
        Console.WriteLine("Service2 created");
    }
}

class Repository : IRepository
{
    public Repository()
    {
        Console.WriteLine("Repository created");
    }
}

class MainViewModel
{
    public MainViewModel(IService service)
    {
        Console.WriteLine("MainViewModel created");
    }

    public void Foo()
    {
        var specificService = ServiceLocator.Current.GetInstance<IService>("MySpecificService");
    }
}

вывод:

Repository created
Service1 created
MainViewModel created
Service2 created

Поскольку вам нужен MainViewModel (может быть, в SimpleIoC вам также необходимо зарегистрировать MainViewModel, в Unity он может разрешать конкретные классы без сопоставления), контейнер пытается его создать, но понимает, что MainViewModel нуждается в IService, и он находит значение по умолчанию из сопоставления, которое является Service1, но он понимает, что Service1 требуется IRepository, и он находит значение по умолчанию, поэтому он может передать Repository в * Конструктор 1053 *, затем экземпляр Service1 для конструктора MainViewModel. Все зависимости разрешены.

Вызов Foo является примером того, как вы можете зарегистрировать более одного типа в одном интерфейсе. Внедрение зависимостей - гораздо более важная тема, но важна ее автоматическая разводка.

...