2010-01-15 2 views
5

Я столкнулся с двумя способами инициализации Views и ViewModels в WPF CAL MVVM.Каков правильный способ инициализации модели и представления в WPF CAL MVVM

1 - Кажется, будет более популярным. Требуется разрешить ViewModel для автоматического разрешения представления. 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 - Кажется намного более чистым и удаляет Вид из ViewModel. Требуется разрешить View для автоматического разрешения ViewModel. Внедряет объекты в представление (не уверен, что это хорошо или нет).

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 
    { 
    } 

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

ответ

3

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

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

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

1

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

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

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

+0

The View свойство в варианте 1 было обнаружено мною в разных примерах, но я согласен, что этого не должно быть. – anon

2

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

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

    ... 

</UserControl> 

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

    ... 
} 
+0

+1 для свойства только для чтения –

1

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

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

Это особенно полезно, если вы хотите указать свой макет, используя 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>(); 
+0

+1 для обозначения разрешения типа не является заданием вида. Я тоже использую этот подход и люблю его. – RMart

Смежные вопросы