Как правильно инициализировать модель и представление в WPF CAL MVVM? - PullRequest
5 голосов
/ 15 января 2010

Я натолкнулся на два способа инициализации Views и ViewModels в WPF CAL MVVM.

1 - кажется более популярным. Требуется разрешить ViewModel для автоматического разрешения View. ViewModel содержит информацию о представлении.

    public interface IView
    {
        void SetModel(IViewModel model);
    }

    public interface IViewModel
    {
        IView View { get; }
    }

    public class View
    {
        public void SetModel(IViewModel model)
        {
            this.DataContext = model;
        }
    }

    public class ViewModel
    {
        private IView view;

        public ViewModel(IView view)
        {
            this.view = view;
        }

        public IView View { return this.view; }
    }

2 - кажется намного чище и удаляет вид из модели представления. Требуется разрешить представление для автоматического разрешения модели представления. Внедрение объектов в представление (не уверен, хорошо это или нет).

    public interface IView
    {
    }

    public interface IViewModel
    {
    }

    public class View
    {
        private IViewModel model;

        public View(IUnityContainer unityContainer)
        {
            this.model = unityContainer.Resolve<IViewModel>();
            this.DataContext = this.model;
        }
    }

    public class ViewModel
    {
    }

Каков принятый метод инициализации представлений и моделей и каковы преимущества и недостатки каждого метода. Должны ли вы вводить объекты в поле зрения?

Ответы [ 4 ]

3 голосов
/ 16 января 2010

Они оба действительны, но # 1 имеет тенденцию быть более тестируемым (по крайней мере, это делает ваши тесты более краткими). Преимущество перед № 2 состоит в том, что он имеет тенденцию быть более явным и делает обслуживание немного более понятным, особенно когда у вас много оборотов, такого рода вещи. Меньше объясняет (хотя это и не причина для принятия, это просто трюизм).

Разница в том, что # 1 называется инъекцией зависимостей , а # 2 называется сервисным местоположением . Их часто путают, потому что они оба обычно используют какой-то контейнер IoC (хотя это не обязательно так).

В конце концов, это вопрос предпочтений, но, как я уже сказал, я думаю, что вы найдете №1 намного проще для тестирования ... вам не нужно будет задействовать интерфейс IUnityContainer при тестировании / макете.

2 голосов
/ 15 января 2010

Я предпочитаю определять модель представления в XAML и предоставлять свойство только для чтения для типизированного доступа:

<UserControl ...>
    <UserControl.DataContext>
        <local:MyViewModel/>
    </UserControl.DataContext>

    ...

</UserControl>

public partial class MyView : UserControl, IMyView
{
    public MyViewModel ViewModel
    {
        get { return this.DataContext as MyViewModel; }
    }

    ...
}
1 голос
/ 21 июля 2011

Проблема с этим кодом заключается в том, что в варианте 2 выпекается больше, чем нужно. Это действительно не нужно и не должно иметь ссылку на контейнер.

Альтернатива позволяет варианту 2 быть таким же тестируемым, как и вариант 1, но концептуально понятнее, поскольку ViewModel никогда не знает о View.

Это особенно полезно, если вы хотите указать макет с помощью файла XML, а не с помощью областей призмы, что позволяет легко настроить макет.

Альтернатива:

public interface IView
{
}

public interface IViewModel
{
}

public class View : IView
{
    private IViewModel model;

    public View(IViewModel m)
    {
        this.model = m;
        this.DataContext = this.model;
    }
}

public class ViewModel : IViewModel
{
}

и где-то еще у вас есть:

Container.RegisterType<IViewModel, ViewModel>( /* appropriate container config */ );
Container.RegisterType<IView, View>(/* appropriate container config */ );

и вы можете создать представление в любом месте с помощью:

Container.Resolve<IViewModel>();
1 голос
/ 15 января 2010

Вариант 1 выглядит примерно справа, дайте представлению ссылку на модель представления.

Мне кажется, что наличие моделей представления со ссылкой на вид немного подозрительно. Это больше похоже на архитектуру типа модель-представление-презентатор. Если у вас есть модели представления, которые интенсивно взаимодействуют с представлением, и для этого вам нужна ссылка на представление, вам лучше разделить модель представления на модель представления, используемую исключительно для привязки данных, и презентатора, который выполняет более сложные взаимодействия.

Вариант 2 выглядит неправильно. Передача ссылки на контейнер ioc в классы - большой запах кода в моей книге. Звонки в контейнер IoC должны быть сведены к минимуму. В большинстве моих приложений я только вызываю контейнер в начале программы, чтобы соединить вещи. Более динамическое создание объекта обычно выполняется с помощью фабричных классов.

...