Подтвердить что ты не робот

Должен ли MVVM ViewModel выполнять преобразование/проверку типов?

Мы просто попадаем в MVVM в WPF.

Мы реализовали наши ViewModels с "сильно типизированными" свойствами (int, double? и т.д.), с которыми мы связываемся в представлении.

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

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

Все это можно обработать с помощью преобразователей значений, я знаю. Но я видел несколько мнений о том, что преобразование не должно рассматриваться как ответственность. То, что вводится в представлении, это строки, а преобразование, проверка и т.д. Должны быть ответственностью ViewModel (поэтому аргумент идет).

Если это так, мы должны переписать большинство свойств в наших моделях ViewModels на строку и предоставить информацию об ошибках через интерфейс IErrorInfo, например. Это, несомненно, сделает для более простой, более компактный XAML в представлении. С другой стороны, преобразование, проверка и т.д. Будет менее декларативной, явной и гибкой с точки зрения дизайнера View.

Похоже, что эти два подхода принципиально разные, поэтому, прежде чем мы решим, мы хотели бы, чтобы некоторые информированные мнения SO по этому вопросу.

Итак: следует ли ViewModels выставлять упрощенный, текстовый интерфейс для просмотра и обработки преобразования внутри? Или должны ли свойства ViewModel выставлять фактические типы данных, оставляя такие задачи для вида обрабатывать?

Update:

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

В частности, мы решили сохранить свойства ViewModel. Основная причина этого - гибкость, которую она дает нам в дизайне представления, и мощь явного, декларативного преобразования/форматирования в XAML.

Я заметил с вами предположение, которое не согласится с нами в этом, что дизайн представления фиксирован и готов. Следовательно, в представлении не должно быть никаких решений относительно преобразования, форматирования и т.д. Но наш - гибкий процесс, и у нас нет всех подробных подробностей пользовательского интерфейса, которые были заранее рассмотрены.

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

Дело в том, что, хотя применение правил бизнес-правил, безусловно, принадлежит ViewModel, нам кажется, что простое преобразование и форматирование - это вещь в виде. Это может звучать как ересь, но на самом деле я не считаю, что преобразование типа в представлении требует модульного тестирования вообще (так долго мы unit test фактические преобразователи типов).

В целом отличная дискуссия, люди, с хорошо сформулированными, информированными мнениями. Спасибо.

4b9b3361

Ответ 1

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

Глядя на шаблон MVVM, насколько я понимаю, точка ViewModel заключается в том, чтобы разоблачить данные таким образом, чтобы View мог понять без каких-либо предположений о том, как будет использоваться представление. Например, предположим, что мы моделируем скорость автомобиля:

public class CarModel
{
    public int MilesPerHour { get; set; }
}

public class CarViewModel
{
    private CarModel _model;

    public int MilesPerHour
    {
        get { return _model.MilesPerHour; }
        set { _model.MilesPerHour = value; }
    }
}

В приведенном выше примере я раскрыл свойство как int, так как это то, что есть в модели. Недостатки этого вы указали в своем вопросе, но главным преимуществом является то, что он дает создателю представления ценную информацию о том, как отображать эти данные. Помните, что мы (как авторы ViewModel) не знаем, как выглядит вид. По идее, что данные являются int, View может использовать текстовое поле или какой-либо другой элемент управления, который принимает только номера (например, циферблат) для отображения информации. Если мы скажем, что мы собираемся форматировать данные так, как мы полагаем, полезно для View, он отнимает у него эту важную энергию.

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

Наконец (и я уверен, что вы это знаете, но ради завершения...) бизнес-логику следует делать в ViewModel. Если мы решаем, что автомобиль не должен проходить выше 70 миль в час, то это не несет ответственности за это. Таким образом, вы все равно окажетесь с каким-то провайдером ошибок, но на уровне бизнеса, а не на уровне отображения.


Хорошо, может быть, это было не окончательно....

Я хотел обратиться к комментариям, сделанным Кентом, и мои мысли не вписывались в комментарий.

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

Моя точка зрения основана на предположении, что вы должны иметь возможность обмениваться просмотрами, они должны быть мимолетными вещами, которые могут меняться в зависимости от требований размера экрана, оборудования, платформы, латентности и среды. Интересный поворот в том, что я действительно никогда не нуждался в этой функции и не видел ничего (помимо доказательств концептуальных приложений), которые когда-либо использовали его, но если мы согласны с тем, что мы не будем использовать его сейчас или в любой момент в будущем и что каждый ViewModel будет работать с одним и только с одним, View, тогда мы также можем вернуться к положению всего кода в файле с кодом и полностью вывести ViewModel - в конце концов, это так тесно связан, что он может быть одним и тем же классом.

В идеале мне бы хотелось, чтобы модель ViewModel могла сказать, что "это значение является int, оно всегда будет int, и вы можете отображать его в любом случае, что вам нравится. Но вы можете вернуть что-нибудь мне, я сделаю все возможное, чтобы он поместился, и если я не могу, я дам вам знать". В основном мое свойство MilesPerHour должно иметь int getter, но объект setter. Таким образом, мнения сохраняют всю необходимую мне информацию, но не нужно беспокоиться о конверсиях или проверке.

Ответ 2

Абсолютно он относится к модели представления по всем обычным причинам, включая:

  • Дизайнеры владеют XAML. Вы хотите, чтобы дизайнеры должны были понимать и реализовывать логику преобразования и логики требуемого типа?
  • Тестируемость. Не хотите ли вы проверить правильность работы вашей логики преобразования и проверки? Это намного сложнее, если он встроен в представление.

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

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

Ответ 3

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

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

Я не уверен, как вы хотели бы реализовать его, я знаю, что классические элементы управления Spinner/NumericUpDown выходят из моды, потому что они не чувствительны к касанию, но я не считаю, что введение такого контроля нарушит чистоту подхода к дизайну или ваших ViewModels. Вы получите номер, который вы можете затем проверить в соответствующем месте, отправить обратную связь через IDataErrorInfo, как обычно, и так далее.:) Этот метод позволяет вам получить лучшее из обоих миров без каких-либо реальных недостатков (кроме создания числового элемента управления).

Ответ 4

Если MVVM ViewModel выполняет тип преобразование/проверка?

Да.

Модель представления представляет собой уровень абстракции между представлением и моделью - идеальное место для выполнения преобразований любого типа (вместо громоздких преобразователей значений). Валидация должна обязательно выполняться как часть модели представления.

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

Один конкретный вопрос, который вы подняли:

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

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

Держите представление немым. У нас нет официальных дизайнеров, наши разработчики - наши дизайнеры, поэтому сохранение вида dumb имеет некоторые преимущества:

  • Мы (разработчики) добираемся, чтобы сохранить наше здравомыслие (XAML несколько менее подробный)
  • Бизнес-логика (включая проверку) остается в модели представления и может включать тестирование

Удачи!

-Z

Ответ 5

Или должны ли свойства ViewModel выставлять фактические типы данных, оставляя такие задачи обрабатываемому виду?

  • Преобразование и шаблоны выполняются в View, потому что они оба являются просто преобразованием values, models и viewmodels в controls! controls доступны только внутри View.

  • Проверка выполняется в ViewModel, поскольку проверка выполняется в соответствии с бизнес-правилами и даже может быть выполнена путем вызова удаленной службы. Просмотр ничего не знает о бизнес-правилах, но знает, как представить результаты проверки.

Если, скажем, неточечное значение вводится в текстовое поле, связанное с числовым свойством

Правильно созданное числовое текстовое поле никогда не позволяет пользователю вводить нечисловое значение.