[WPF] MVVM, Валидация
От: karbofos42 Россия  
Дата: 20.04.20 08:04
Оценка:
Как-то раньше меня данный вопрос так не волновал, а тут никак не могу определиться как лучше сделать.

VM часто сводится к набору свойств вида:
public int Value
{
  get
  {
    return model.Value;
  }
  set
  {
    model.Value = value;
    OnPropertyChanged();
  }
}


при разработке GUI есть такая рекомендация: давать пользователю вводить почти что угодно, но помечать как ошибка и максимально понятно описывать ошибку.
Допустим, мне в TextBox нужно ввести озвученный выше Value.
Стандартных подхода вроде бы 3:
1) в set'ере кидать исключения — как-то слишком жёстко и потом наличие ошибок собирать в VM как-то не очевидно и сильно привязано к WPF
2) ValidationRule — для каждой проверки создавать свой класс выглядит не очень хорошо
3) IDataErrorInfo/INotifyDataErrorInfo — не получится поймать ошибку, когда в TextBox ввели текст
Можно комбинировать подход 1 и 3, но как-то тоже не выглядит хорошим решением.

В простых случаях в VM просто создавал Value как string, а не int и уже в методе валидации проверял на ошибку приведения к числу.
Везде так делать как-то тоже не выглядит хорошей идеей.
Кроме данного случая есть и всякие enum, которые в модели не nullable, а вот в окне вполне может пользователь ничего не выбрать.
А еще всякие составные проверки, когда А < Б и более сложные определения.

Какая-то может есть устоявшаяся практика, где нормально вся валидация собирается в одном месте и ViewModel знает есть ли в ней ошибки без переборов контролов и т.п.?
Сколько ни пытался найти информации, а везде только простейшие примеры, показывающие как всё легко и просто.
Re: [WPF] MVVM, Валидация
От: takTak  
Дата: 20.04.20 08:19
Оценка:
K>3) IDataErrorInfo/INotifyDataErrorInfo — не получится поймать ошибку, когда в TextBox ввели текст

очень даже получится: просто надо ещё стиль для ошибки доопределить и всё
https://social.technet.microsoft.com/wiki/contents/articles/22506.asynchronous-validation-in-wpf-using-the-mvvm-pattern-and-inotifydataerrorinfo.aspx
Re: View model
От: Qbit86 Кипр
Дата: 20.04.20 08:29
Оценка:
Здравствуйте, karbofos42, Вы писали:

K>В простых случаях в VM просто создавал Value как string, а не int и уже в методе валидации проверял на ошибку приведения к числу.

K>Везде так делать как-то тоже не выглядит хорошей идеей.

Почему? VM — это же «view model» (модель представления), а не «model view» («представление модели»). Конвертер на стероидах. Его поля — это сконвертированная модель, а не сырая.

K>Кроме данного случая есть и всякие enum, которые в модели не nullable


См. рекомендацию из Framework design guidelines:

✔️ DO provide a value of zero on simple enums.

Consider calling the value something like "None."
— https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/enum

Глаза у меня добрые, но рубашка — смирительная!
Re: [WPF] MVVM, Валидация
От: Kolesiki  
Дата: 20.04.20 15:34
Оценка: -2
Здравствуйте, karbofos42, Вы писали:

K>MVVM, Валидация

K>... везде только простейшие примеры, показывающие как всё легко и просто.


В этом и есть вся суть теоретиков, покрытых академической пылью кабинетов — рисовать на бумажках свои красивые теории и расписывать, какие мы все дураки, что не следуем дословно их видению идеальных программ! Это на чертежах можно смело "отделять ГУЙ от логики" одной красной линией, на деле там 5 перпендикулярных линий и круг в форме зайчика.

На практике лучше не выпендриваться и иногда даже костылить. Пример насвкидку по изменению "инт" проперти:

{текстовый контрол}--- на событие "изменилось значение" тупо хардкодим проверку, что строка вообще какой-то вменяемый int. Если нет — подсвечиваем рамку красным.
В закрытии формы смело берём отвалидаченное выражение и конвертим в инт — ошибок уже не будет. А теперь присваиваем инт низлежащей проперти (да-да, руками!). Если у проперти есть доп. валидация (например, на значения минут), ловим исключение и красиво показываем юзеру — пусть редактирует заново.
В данной схеме вообще нет никаких MVVM! Ибо оверхэд и тухлые теории. Есть визуальная форма + модель, совмещённая с вьюмоделью. Таким образом, вместо трёх сущностей у нас всего две и обе вменяемо управляемы.
Отредактировано 20.04.2020 15:35 Kolesiki . Предыдущая версия .
Re[2]: [WPF] MVVM, Валидация
От: karbofos42 Россия  
Дата: 20.04.20 15:45
Оценка:
Здравствуйте, takTak, Вы писали:


K>>3) IDataErrorInfo/INotifyDataErrorInfo — не получится поймать ошибку, когда в TextBox ввели текст


T>очень даже получится: просто надо ещё стиль для ошибки доопределить и всё

T>https://social.technet.microsoft.com/wiki/contents/articles/22506.asynchronous-validation-in-wpf-using-the-mvvm-pattern-and-inotifydataerrorinfo.aspx

Если биндить TextBox к свойству int, то не int значения просто не дойдут до этого варианта валидации и отвалятся раньше. В итоге во ViewModel будет записано последнее валидное значение и нужно как-то вручную получать отдельно подобного рода ошибки ввода.
Re[3]: [WPF] MVVM, Валидация
От: takTak  
Дата: 20.04.20 15:52
Оценка:
K>>>3) IDataErrorInfo/INotifyDataErrorInfo — не получится поймать ошибку, когда в TextBox ввели текст

T>>очень даже получится: просто надо ещё стиль для ошибки доопределить и всё

T>>https://social.technet.microsoft.com/wiki/contents/articles/22506.asynchronous-validation-in-wpf-using-the-mvvm-pattern-and-inotifydataerrorinfo.aspx

K>Если биндить TextBox к свойству int, то не int значения просто не дойдут до этого варианта валидации и отвалятся раньше. В итоге во ViewModel будет записано последнее валидное значение и нужно как-то вручную получать отдельно подобного рода ошибки ввода.


ну, сделай во ViewModel не int, а string, если так надо...

кроме того, ты можешь обойтись и int, если к твоему текстбохску добавишь какой-нибудь тул-тип, который бы объяснял пользователю, что допустимы только целочисленные значения или ещё что...

это всё стандартные вещи, которым 20 лет в обед...
Re[2]: View model
От: karbofos42 Россия  
Дата: 20.04.20 15:59
Оценка:
Здравствуйте, Qbit86, Вы писали:

Q>Здравствуйте, karbofos42, Вы писали:


K>>В простых случаях в VM просто создавал Value как string, а не int и уже в методе валидации проверял на ошибку приведения к числу.

K>>Везде так делать как-то тоже не выглядит хорошей идеей.

Q>Почему? VM — это же «view model» (модель представления), а не «model view» («представление модели»). Конвертер на стероидах. Его поля — это сконвертированная модель, а не сырая.


K>>Кроме данного случая есть и всякие enum, которые в модели не nullable


Q>См. рекомендацию из Framework design guidelines:

Q>

✔️ DO provide a value of zero on simple enums.

Q>Consider calling the value something like "None."
Q>— https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/enum


К сожалению ни модель, ни enum поменять не могу, но в большинстве enum есть такое значение.

Приводит enum скорее как альтернативный пример, по факту чаще встречается вариант с вложенной моделью типа:
class ModelA
{
  public ModelB B
  {
    get => _b;
    set => _b = value ?? throw new Exception();
  }
}

Просто проблема выглядит тут однообразно: в модель здесь и сейчас не могу записать значение, которое может выбрать пользователь, и нормально это как-то программно обработать.
Самому больше нравится, когда в окне меняется VM и только по кнопке Сохранить данные выгружаются в Модель, а Отмена просто ничего не делает.
В текущей ситуации этому мешает сложная модель, в которой так же содержатся куски бизнес-логики. Если я сразу не поменяю Модель, то не смогу и сделать часть валидации ввода пользователя.
Частные случаи конечно можно разрулить по месту и вводом дополнительных свойств и прочими хитростями и глупостями, но как-то хотелось найти подобие серебряной пули, чтобы всё везде однообразно было
Re[2]: [WPF] MVVM, Валидация
От: karbofos42 Россия  
Дата: 20.04.20 16:03
Оценка:
Здравствуйте, Kolesiki, Вы писали:

K>Здравствуйте, karbofos42, Вы писали:


K>>MVVM, Валидация

K>>... везде только простейшие примеры, показывающие как всё легко и просто.

K>

K>В этом и есть вся суть теоретиков, покрытых академической пылью кабинетов — рисовать на бумажках свои красивые теории и расписывать, какие мы все дураки, что не следуем дословно их видению идеальных программ! Это на чертежах можно смело "отделять ГУЙ от логики" одной красной линией, на деле там 5 перпендикулярных линий и круг в форме зайчика.

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

K>На практике лучше не выпендриваться и иногда даже костылить. Пример насвкидку по изменению "инт" проперти:


K>{текстовый контрол}--- на событие "изменилось значение" тупо хардкодим проверку, что строка вообще какой-то вменяемый int. Если нет — подсвечиваем рамку красным.

K>В закрытии формы смело берём отвалидаченное выражение и конвертим в инт — ошибок уже не будет. А теперь присваиваем инт низлежащей проперти (да-да, руками!). Если у проперти есть доп. валидация (например, на значения минут), ловим исключение и красиво показываем юзеру — пусть редактирует заново.
K>В данной схеме вообще нет никаких MVVM! Ибо оверхэд и тухлые теории. Есть визуальная форма + модель, совмещённая с вьюмоделью. Таким образом, вместо трёх сущностей у нас всего две и обе вменяемо управляемы.

Это уж слишком жёсткий костыль. И без этого хватает мест где кто-то что-то забыл поменять или опечатался, чтобы и такие вещи везде вручную прописывать. Слишком дорого поддержка такого кода выйдет.
Лучше уж я добавлю оверхед корявеньким MVVM, как понимаю, чем так сурово поступлю в 2020 году
Re[4]: [WPF] MVVM, Валидация
От: karbofos42 Россия  
Дата: 20.04.20 16:12
Оценка:
Здравствуйте, takTak, Вы писали:

K>>>>3) IDataErrorInfo/INotifyDataErrorInfo — не получится поймать ошибку, когда в TextBox ввели текст


T>>>очень даже получится: просто надо ещё стиль для ошибки доопределить и всё

T>>>https://social.technet.microsoft.com/wiki/contents/articles/22506.asynchronous-validation-in-wpf-using-the-mvvm-pattern-and-inotifydataerrorinfo.aspx

K>>Если биндить TextBox к свойству int, то не int значения просто не дойдут до этого варианта валидации и отвалятся раньше. В итоге во ViewModel будет записано последнее валидное значение и нужно как-то вручную получать отдельно подобного рода ошибки ввода.


T>ну, сделай во ViewModel не int, а string, если так надо...


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

T>кроме того, ты можешь обойтись и int, если к твоему текстбохску добавишь какой-нибудь тул-тип, который бы объяснял пользователю, что допустимы только целочисленные значения или ещё что...


T>это всё стандартные вещи, которым 20 лет в обед...


Меня устраивает, что в IDataErrorInfo сам собираешь ошибки внутри ViewModel и никуда больше не лазиешь. Стандартные вещи в итоге похоже приводят к тому, что либо число как текст хранить, либо потом в валидации лезть в Validation и проверять, что нигде в контролах не осели ошибки ввода.
Хочется красоты и изящества, в общем
Re: [WPF] MVVM, Валидация
От: ksg71 Германия  
Дата: 20.04.20 18:19
Оценка: 1 (1) +1
Здравствуйте, karbofos42, Вы писали:

K>Как-то раньше меня данный вопрос так не волновал, а тут никак не могу определиться как лучше сделать.


K>VM часто сводится к набору свойств вида:

K>
K>public int Value
K>{
K>  get
K>  {
K>    return model.Value;
K>  }
K>  set
K>  {
K>    model.Value = value;
K>    OnPropertyChanged();
K>  }
K>}
K>


K>при разработке GUI есть такая рекомендация: давать пользователю вводить почти что угодно, но помечать как ошибка и максимально понятно описывать ошибку.

K>Допустим, мне в TextBox нужно ввести озвученный выше Value.

вот тут лучше как раз давать вводить максимально "типизированно", чтобы контрол уже имел свойство нужного типа
или исключал проблемы при конверсии
никто ведь не делает ввод булевого значение из текстбокса куда надо написать true или false — используют checkbox
и тогда INotifyDataErrorInfo отлично все покрывает
вот тут кстати неплохо написано
Das Reich der Freiheit beginnt da, wo die Arbeit aufhört. (c) Karl Marx
Отредактировано 20.04.2020 18:23 ksg71 . Предыдущая версия . Еще …
Отредактировано 20.04.2020 18:21 ksg71 . Предыдущая версия .
Re[2]: [WPF] MVVM, Валидация
От: karbofos42 Россия  
Дата: 21.04.20 07:11
Оценка:
Здравствуйте, ksg71, Вы писали:

K>Здравствуйте, karbofos42, Вы писали:


K>>Как-то раньше меня данный вопрос так не волновал, а тут никак не могу определиться как лучше сделать.


K>>VM часто сводится к набору свойств вида:

K>>
K>>public int Value
K>>{
K>>  get
K>>  {
K>>    return model.Value;
K>>  }
K>>  set
K>>  {
K>>    model.Value = value;
K>>    OnPropertyChanged();
K>>  }
K>>}
K>>


K>>при разработке GUI есть такая рекомендация: давать пользователю вводить почти что угодно, но помечать как ошибка и максимально понятно описывать ошибку.

K>>Допустим, мне в TextBox нужно ввести озвученный выше Value.

K>вот тут лучше как раз давать вводить максимально "типизированно", чтобы контрол уже имел свойство нужного типа

K>или исключал проблемы при конверсии
K>никто ведь не делает ввод булевого значение из текстбокса куда надо написать true или false — используют checkbox
K>и тогда INotifyDataErrorInfo отлично все покрывает
K>вот тут кстати неплохо написано

Спасибо за ссылку, посмотрю на досуге.
Разница чисел в том, что bool из буфера никто не вставляет и мало возможных значений.
Меня самого раздражает, когда в поле ввода внезапно ничего не вставляется. Не то лишний пробел где-то затесался и мешает, не то число в диапазон не попадает, не то в буфере просто что-то не то находится.
Был бы более подходящий контрол в WPF из коробки, тогда его бы использовал, но такого нет и банальный TextBox выглядит чуть ли не единственным вариантом.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.