Наследование MVVM с моделями представления - PullRequest
18 голосов
/ 10 июня 2009

Мне интересно, как приблизиться к наследованию с помощью View Models в шаблоне MVVM. В моем приложении у меня есть модель данных, похожая на следующую:

class CustomObject
{
    public string Title { get; set; }
}

class CustomItem : CustomObject
{
    public string Description { get; set; }
}

class CustomProduct : CustomItem
{
    public double Price { get; set; }
}

В моем приложении у меня есть класс ViewModelBase, а затем я собирался иметь следующие модели представления:

  • CustomObjectViewModel
  • CustomItemViewModel
  • CustomProductViewModel

Грубая реализация CustomObjectViewModel будет выглядеть следующим образом:

class CustomObjectViewModel : ViewModelBase
{
    private readonly CustomObject _customObject;

    public CustomObjectViewModel( CustomObject customObject )
    {
        _customObject = customObject;
    }

    public string Title
    {
        // implementation excluded for brevity
    }
}

Мне кажется логичным, что мои модели представления будут расширяться так же, как моя модель (CustomItemViewModel расширяет CustomObjectViewModel и т. Д.). Однако я заметил, что по мере перехода по дереву наследования я буду добавлять дополнительные ссылки к тому же объекту. Мне это кажется довольно чрезмерным, и мне было интересно, как подойти к этой проблеме и можно ли сделать ее намного чище.

Ответы [ 4 ]

19 голосов
/ 10 июня 2009

Как правило, я бы порекомендовал вам не иметь наследования между различными классами ViewModel , а вместо этого иметь их наследование напрямую от общего абстрактного базового класса.
Это позволяет избежать ненужной сложности с помощью загрязнение интерфейсов классов ViewModel членами, которые идут вверх по иерархии, но не полностью связны с основной целью класса.
Связывание, которое приходит с наследованием, также будет вероятно, затруднит изменение класса ViewModel, не затрагивая ни один из его производных классов.

Если ваши классы ViewModel всегда будут ссылаться на один объект Model, вы можете использовать универсальные шаблоны для инкапсуляции этого правила в базовый класс:

public abstract class ViewModelBase<TModel>
{
    private readonly TModel _dataObject;

    public CustomObjectViewModel(TModel dataObject)
    {
        _dataObject = dataObject;
    }

    protected TModel DataObject { get; }
}

public class CustomObjectViewModel : ViewModelBase<CustomObject>
{
    public string Title
    {
        // implementation excluded for brevity
    }
}

public class CustomItemViewModel : ViewModelBase<CustomItem>
{
    public string Title
    {
        // implementation excluded for brevity
    }

    public string Description
    {
        // implementation excluded for brevity
    }
}
5 голосов
/ 11 июня 2009

Связано с комментарием выше Энрико. ViewModels не должен быть тесно связан с представлениями, это должно быть наоборот. Представления должны быть слабо связаны с ViewModels. ViewModel не должен знать о представлении, это позволяет вам легко выполнить модульное тестирование ViewModel. Все взаимодействия между представлениями с ViewModel должны реализовываться через свойства в ViewModel (свойства ICommand для действий и другие свойства для привязки данных).

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

Предоставляя класс ViewModel, который в основном просто предоставляет свойства, он должен позволить вам перенести это в любую среду представления и использовать весь код, который вы использовали ранее. Другими словами, при правильной реализации вы можете поместить свою сборку ViewModels в приложение ASP.NET MVC и привязать представление к свойствам без изменения кода.

Хорошая статья об основах MVVM: эта. Я действительно думаю, что MVVM - лучшая вещь для разработки пользовательского интерфейса. Очевидно, что мы не можем все использовать его, потому что это требует создания приложения с нуля, используя подход MVVM, но когда вы создаете новое приложение, это не проблема.

Единственный недостаток, который я имею с ICommand, заключается в том, что он находится в сборке PresentationCore, которая в основном предназначена для WPF. Если Microsoft хочет слабой связи, она должна быть в другой сборке.

4 голосов
/ 12 июня 2009

Я думаю, что проблема здесь в том, что должен быть один ViewModel для каждого View, а не один ViewModel для каждой модели.

Причина этого довольно очевидна, поскольку вы можете установить только один объект в качестве DataContext, этот объект должен быть ViewModel для этого представления.

4 голосов
/ 10 июня 2009

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

class CustomObjectViewModel : ViewModelBase
{
    protected readonly CustomObject CustomObject;

    public CustomObjectViewModel( CustomObject customObject )
    {
        CustomObject = customObject;
    }

    public string Title
    {
        // implementation excluded for brevity
    }
}

class CustomItemViewModel : CustomObjectViewModel 
{
    protected CustomItem CustomItem  { get { return (CustomItem)CustomObject; } }

    public CustomItemViewModel( CustomItem customItem )
        :base(customItem)
    {
    }
}

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...