Внедрение Silverlight Constructor в модель View + Design Mode - PullRequest
10 голосов
/ 27 октября 2010

Я пытаюсь справиться с написанием тестируемых ViewModels в Silverlight 4. Я сейчас использую MVVM light.

Я использую AutoFac, и IoCContainer отлично справляется со своей задачей. Однако, чтобы вставить в конструктор ViewModels, которые связаны с представлениями, у меня есть этот конструктор цепочки:

    public UserViewModel() : this(IoCContainer.Resolve<IUserServiceAsync>())
    {

    }

    public UserViewModel(IUserServiceAsync userService) 
    {
        if (this.IsInDesignMode) return;

        _userService = userService;
    }

Который не кажется чистым, но это лучший вариант, который я нашел до сих пор. Это работает, и мое приложение работает как нужно, и тестируется с инвертированным управлением.

Однако, с моей виртуальной машиной, связанной с моим взглядом, вот так:

 <UserControl.DataContext>
            <ViewModel:UserViewModel />
 </UserControl.DataContext>

В моих атрибутах страницы XAML режим разработки в VS2010 и Blend не работает.

Есть ли лучший способ добиться того, что я пытаюсь в Silverlight, который все еще работает в режиме дизайна? Потеря режима проектирования не является нарушителем, но будет полезна при изучении XAML. Хотя чистильщик, не прикованный цепью, был бы хорош!

Я думаю, что, возможно, возможно использовать AutoFac / IoC для разрешения моделей представления в представления, в отличие от подхода разметки XAML, описанного выше, и пойти по этому пути?

Спасибо.

1 Ответ

10 голосов
/ 27 октября 2010

Вместо реализации первого конструктора, я предлагаю вам реализовать ViewModelLocator, например так:

public class ViewModelLocator
{

    IoCContainer Container { get; set; }

    public IUserViewModel UserViewModel
    {
        get
        {
            return IoCContainer.Resolve<IUserViewModel>();
        }
    }

}

Затем в XAML вы объявляете локатор как статический ресурс:

<local:ViewModelLocator x:Key="ViewModelLocator"/>

Пока вы инициализируете свое приложение, необходимо предоставить локатору экземпляр контейнера:

var viewModelLocator = Application.Current.Resources["ViewModelLocator"] as ViewModelLocator;
if(viewModelLocator == null) { // throw exception here }
viewModelLocator.Container = IoCContainer;

Тогда в XAML вы можете аккуратно использовать ресурс:

<UserControl
    DataContext="{Binding Path=UserViewModel, Source={StaticResource ViewModelLocator}}"
    />
    <!-- The other user control properties -->

Во время разработки вы можете реализовать MockViewModelLocator:

public class MockViewModelLocator
{

    public IUserViewModel UserViewModel
    {
        get
        {
            return new MockUserViewModel();
        }
    }

}

Объявите это в XAML соответствующим образом:

<local:MockViewModelLocator x:Key="MockViewModelLocator"/>

И, наконец, используйте его в своем пользовательском элементе управления:

<UserControl
    d:DataContext="{Binding Path=UserViewModel, Source={StaticResource MockViewModelLocator}}"
    DataContext="{Binding Path=UserViewModel, Source={StaticResource ViewModelLocator}}"
    />
    <!-- The other user control properties -->

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

Таким образом, вы не потеряете данные времени проектирования и не должны жертвовать чистотой методологии внедрения зависимостей в ваших моделях представления.

Надеюсь, это поможет.

...