Лапшекодим валидацию, или запрещаем вводить неправильные данные?
Попытался тут заюзать Range атрибут для валидации моделей в WPF. А мне сказали, что он сам не заводится, а надо реализовывать интерфейс IDataErrorInfo. Обычно все примеры с ним для веб проектов (типа ASP.NET MVC) приводятся - там типа код из коробки есть, который модель под капотом валидирует, поэтому тебе кажется, что валидация происходит автоматически - достаточно просто добавить атрибутов. При попытке перенести эту "простоту" в тот же WPF ничего из коробки не заводится так же легко, как в веб проектах.
И то верно, когда привязываешь в XAML
Path=(Validation.Errors)[0].ErrorContent}
То там ничего нет без прописывания валидации в IDataErrorInfo. Сам RangeAttribute ничего не валидирует.
Для реализации валидации через IDataErrorInfo предлагается писать тонну лапшекода. Либо через магию рефлексии, либо через совсем уж лапшу с перебором всех пропертей вручную. Я всё думал, что лыжи-то не едут. Либо я тупой, либо лыжи всё же авно? Вспомнил, что я этот вопрос для себя закрыл ещё давно, и решил, что эту лапшу писать не буду. Штука в том, что они в этих статьях как правило на вьюхе используют обычный текстбокс, из которого берут строку, пытаются парсить её в число и валидируют. Ну ладно парсить, но валидировать-то тоже вручную приходится. И я давно от этого дерьма отказался в пользу правильных контролов. Вместо того, чтобы вытаскивать той же рефлексией из модели долбаный атрибут (а более удобного способа доступа к ним в Дотнете нет), потом его свойства и проверять введённые значения по ним, я ввожу прямо в модели обычные свойства типа Value, Min, Max. А потом, ска, тупо привязываю их к правильному контролу, типа NumericUpDown, который из коробки имеет те же свойства Value, Min, Max и не даёт ввести значения вне диапазона. Вуаля - не надо лапшекодить.
А если ещё добавить, что сериализация моделей с кучей валидирующих атрибутов тот ещё квест по сравнению с сериализацией обычных свойств Value, Min, Max... Или есть всё же простые варианты?
Короче, в чём суть. Вместо того, чтобы лапшекодить долбаную валидацию, не проще добавить контролы с ограничениями для вводимых чисел, строк и тому подобному? Текстбокс с проверкой длины введённой строки и фильтру символов, текст бокс с переключателями для числе и заданием диапазона (NumericUpDown), и т.д.
О, да, мать-перемать! Городим забор из наследования базовых классов с валидацией и прочим, тонны кода с линком, словарями и делегатами по вытаскиванию атрибутов и пропертей, кастомные поведения, прогресс валидации - о да, конечно, только это бы и делал с утра до вечера! Чел поди месяц пыхтел над этой бадьёй. Статью тиснул, где-то на SO я его ответы видел, где он тоже советовал основательно реализовывать IDataErrorInfo.
Кого-то хлебом не корми - дай усложнить всё до упора. ))
Одно непонятно. Как-то в веб-проектах добились, что разрабу не надо самому эти простыни писать. Ну добавил атрибут в модель и оно само под капотом валидируется. Во вьюхе привязал контрол к сообщению об ошибке, которое туда как-то попало, но мне и пофиг, как - главное, что попало. Почему в других местах, типа того же WPF, нужно всё руками вспахивать?
Эта же проблема с долбаными атрибутами возникает, когда делаешь MVVM в WPF и вообще подобные многослойки. Прописываешь в самом нижнем слое (типа модель) валидирующие атрибуты. А теперь нужно всю эту валидацию поднять на уровень выше - скажем, модель представления. Что делать будете? Лапшекодить-рефлексировать, вытаскивая атрибуты из модели? А как в атрибуты вью модели это всё поместите? Атрибуты-то во время выполнения кода не задаются - только при написании. Ну я обычно во вью модели и делаю валидирующие ограничения (типа Min и Max) в виде обычных свойств. А если их уже во втором слое в виде обычных свойств делаешь, то почему бы сразу в первом же слое их такими не сделать? К чему возьба с атрибутами и потом с рефлексией по их вытаскиванию?
Навеяло, как один знакомый сходил в одну крутую новосибскую контору лет 12-15 назад. Там ему код показали - он сказал, что они теперь всё на атрибутах делают - валидацию, шмалидацию. Модно типа теперь так. Правда, не сказал, как они теперь с этим всем ипуца и стоило ли оно того. Но я тогда зелёный был и про атрибуты лишь мельком слышал. Подумал, ну раз у них всё на атрибутах теперь, значит контора точно крутая. Ну не будет же одна из самых крутых контор Новосиба веников вязать?
Ещё доводы за перенос валидации ввода в контролы, а не в классы бизнес-логики. Начинаете новый класс модели. Если реализовывать валидацию в базовом классе, то каждый раз надо унаследоваться от него. Не задолбает ли? А вот если валидация в контролах, то ничего дополнительного сверх обычного делать не надо.
Подход же у вышеописанных товарищей с простынями рефлексии какой-то странный - мы во вьюхе получаем ввод, спускаем его на слой модели, в модели валидируем и поднимаем отчёт о валидации (ошибки и отвалидированное значение) обратно во вьюху. Все эти путешествия данных туда-сюда при простом вводе (даже не сохранении введённых значений, а просто валидации "на лету") во-первых дико связывают слои, а во-вторых - усложняют код.
Естественно, это для простых проектов - модель плюс вью модель. Если у вас там десятки слоёв, и на каждом своя валидация, то там другой подход может быть. Но суть та же - вместо гоняния данных из верхних слоёв в самые нижние и обратно, лучше всё делать на как можно более верхнем слое, где вводятся данные.
Ещё доводы за
Не нужно искать универсальное решение. Для каждого проекта будет свое наиболее подходящее
https://docs.devexpress.com/WPF/7076/controls-and-librarie...
https://docs.devexpress.com/WPF/6945/controls-and-librarie...
https://docs.devexpress.com/WPF/6933/controls-and-librarie...
Вот этого дядьку с его лапшевалидацией
https://github.com/EmmanuelDURIN/wpf-attribute-validation/...
я тоже встречал на SO по этой теме.
Хорошо, конечно, иметь кучу умных контролов вместо стандартной куцей поставки, в которой всё надо из текстбоксов брать.
Как будете сериализовывать и десериализовывать объект с атрибутами валидации? Или атрибуты не сериализуются?
Вот этого дядьку с его лапшевалидацией
А чем не нравится то?
public class Contact : ValidatorBase { [Required(ErrorMessage = " Name is required.")] [StringLength(50, ErrorMessage = "No more than 50 characters")] [Display(Name = "Name")] public string Name { get; set; } }
Вот если бы это так и работало, без той лапши, на которую я ссылку дал.
А теперь скажите, зачем нужен валидатор StringLength, если я могу использовать контрол с ограничением по длине строки?
По мне, луче иметь такую модель (проперти для примера)
Name
NameMaxLength
DisplayName
Age
AgeMin
AgeMax
чем такую
[StringLength]
[Display]
Name
[Range]
Age
Первая и привязывается к чему угодно без проблем, и сериализуется тоже без проблем. И безо всякого лапшекода. Имя привязывается к контролу со встроенным ограничителем на длину строки, и к этому же ограничителю привязывается NameMaxLength. Когда вводишь больше ограничителя, то просто прекращается ввод - не надо никаких сообщений об ошибках. То же с возрастом - привязываем его не к голому текстбоксу, а к нормальному NumericUpDown, в котором есть проверка диапазона, границы которого тоже легко привязываются к свойствам модели.
Всё! Не надо лапши, рефлексии, обязательного базового класса с реализацией допотопных неудобных интерфейсов, и трахания с сериализацией. Вам только кажется, что атрибуты это красиво и удобно. Оно красиво толкьо когда их один-два и они коротко объявлены. А когда каша из атрибутов с кучей установок их свойств (типа притаранить локализованное сообщение об ошибке - укажи словарь, укажи ключ, укажи собственно свойства атрибута), то вся красота и лаконичность быстро исчезают. Вот это что, читаемо (смотри ниже)? А я тут всего два атрибута написал. Некоторые навешивают по пять-шесть. Можно и в одну строку написать - будете скроллить экран по горизонтали. Особенно если у вас ноутбук с маленьким экраном. Писал, писал я подобную фигню, вытаскивал данные из атрибутов рефлексией... а потом подумал - а нафига оно надо? И стал всё в обычных пропертях писать.
[NameDescription( resourceType: typeof(Namespace1.Namespace2.Namespace3.Namespace4.Strings), name: "AAAName", description: "AAADescription")] [Range( 1.0, 20.0, ErrorMessageResourceType: typeof(Namespace1.Namespace2.Namespace3.Namespace4.Strings), ErrorMessageResourceName : "AAAErrorMessage")] public double AAA { get; set; } = 1.6;
Чем мне не нравятся атрибуты и прочие данные, запиханные в рефлексию - они скрытые. Вот приходит к тебе объект класса, у него свойтсва - вот его данные. А нифига - у него ещё глобальные данные класса есть. Просканируй через рефлексию на наличие атрибутов. Т.е. ты должен изучить исходные код класса, чтобы знать, как с ним работать, чтобы увидеть, что там в глобальных данных куча инфы запрятана, которую ты тоже должен знать и как-то её достать.
Это, лять, как с ссылками на файлы с кодом.
Какого хрена мне талдычат, что всё должно быть прозрачно и меньше связано, а сами пихают данные в скрытые хранилища и вводят неявные связи между проектами?
А если пользователь захочет сделать кастомный интерфейс и на нескольких языках? У нас для гостиницы и ресторанов можно было визуально весь интерфейс настраивать - формы, меню, горячие клавиши, для этого сделали специальный инструмент, спомощью которого можно было создавать кастомный формы и отчёты, как это было в Visual FoxPro, и в Microsoft Access.
А какая разница? Для разных культур так же вытаскиваете из словарей по ключам нужное значение и присваиваете свойству. Просто атрибут это делает за вас - само присваивание. Но прописываете всё (класс со словарём, ключ) вы всё равно сами. В конечном счёте с атрибутом даже больше возни - сам атрибут ещё надо оформить.
К настраиваемому виду интерфейса атрибуты вообще не относятся, по-моему. Разве что вы через них как-то эти настройки реализуете? Ну так это явно не обязательный и не единственный путь.
Какого хрена мне талдычат, что всё должно быть прозрачно и меньше связано, а сами пихают данные в скрытые хранилища и вводят неявные связи между проектами?
я не сишарпист и даже не программист, но могу предположить два варианта:
1. Кто программировал усложнял не специально, он просто по другому не мог, так научили работать с "паттернами",
Гдето читал, китайцы так программируют, заучивают код целыми страницами, и потом решают проблему - подходящим куском.
2. Кто программировал усложнял СПЕЦИАЛЬНО.
Вот ты сколько раз уже залетаешь с шашкой наголо - все дураки, ты Д'Артаньян? а потом разбираешься и признаёшь свою ошибку.
Теперь представь, тебе доверили доработать и обновить систему, ты лезешь и лепишь код простой как ситцевые трусы, документация, комментарии...
Что произойдёт? Если каждый школьник может понять и сопровождать - то спрашивается, зачем платить больше? Тебя выпнут и посадят практиканта,
А умные семизнаки как делают? Правильно, наваяют хитроумно, сам шеф не понимает, а семизнак такой - эта конструкция повысит производительность на 30 процентов!
И пофиг что функция вызывается раз в месяц, а код перелопачивать и понимать никто не будет, так семизнак остаётся при деле, и ещё идёт на повышение, незаменим ценный сотрудник.

Вот если бы это так и работало
Как это все реализуется вроде бы должно быть безразлично. Подключили либу и работаем.
А теперь скажите, зачем нужен валидатор StringLength, если я могу использовать контрол с ограничением по длине строки?
Ну давайте в проперти грид засуньте подобный контрол, да и контролов на все случаи не наберёте, когда нужно может и это, а может и это еще проверить, да и пользователю сообщить об ошибке.
По мне, лучше иметь такую модель
Опять таки в каком то частом случае. А если иметь хотя-бы пяток полей с мин и мах, то получаем уже 15 пропертей которые нужно все не забыть использовать правильно.
не надо никаких сообщений об ошибках
Очень даже надо. Вот помню где то было поле с 1000 символами. Так во первых, знаешь это заранее, а во вторых видно сколько еще можно дописать.
и сериализуется тоже без проблем
Это вообще клёво. Записали с ограничением в 16 лет, а после изменили на 18, и вдруг оказывается, что после чтения будет всё равно на 16
И пофиг что функция вызывается раз в месяц, а код перелопачивать и понимать никто не будет, так семизнак остаётся при деле, и ещё идёт на повышение, незаменим ценный сотрудник.
Вы правы пожалуй. Только так семь знаков и домик во Флориде и зарабатываются.
да и пользователю сообщить об ошибке.
Моя идея - пользователю не нужно будет сообщать об ошибке, если изначально делать контрол, который не даст ему сделать ошибку. Когда у тебя на все случаи жизни один тип поля ввода - текст бокс без ограничений, тогда и требуются сотни строк валидаций и прочей лапшы.
И я говорю не про контролы на все случаи жизни, а на 99% этих случаев. NumericUpDown и всякие маскированные текстбоксы с прочими ограничениями - давно уже само собой разумеющееся для любого набора контролов должно быть. У нормальных поставщиков контролов оно уже давно так и есть.
Хочется ведь сериализовывать данные с полями валидации.
Сохранили вот данные пользователя, а затем восстановили. А между этим в программе ограничения изменились.
Если такая проблема, то не сериализуйте поля валидации. Или при десериализации полей валидации ранее сериализованных объектов считайте их устаревшими относительно данных в текущей запущенной сборке.
Возможно, что для атрибутов просто свой механизм сериализации будет - не пересекающийся с механизмом для простых данных. Т.е. отдельно сохраняем модель, и отдельно - данные атрибутов этой модели.
Суть-то в том, что когда сериализовать не надо, то проблем нет в любом случае, а когда надо, то с атрибутами приходится возиться. А как их сериализовать? А обычно создаёшь модель для сериализации, куда атрибуты выводишь в виде обычных свойств, или пишешь для сериализатора всякие конвертеры, которые делают примерно то же самое - вытаскивают данные из атрибутов и сериализуют их.
И да, пачка свойств выглядит читаемее, чем пачка атрибутов с кучей параметров.
У нормальных поставщиков контролов оно уже давно так и есть.
А кто сказал что МС - нормальный поставщик контролов? Они делают только то что нужно лично им.
Поэтому во всех нормальных конторах юзаются всякие девэкспрессы и прочие контрол-паки. Да и от самой МС есть какие-то бесплатные - Fluent чего-то там.
2. Кто программировал усложнял СПЕЦИАЛЬНО.
А если вскроется? Приходит какой-нибудь мурр на проект, а там зелёные сеньёры. Он такой про себя - "хыхыыы, все лохи, а я семизнак... щас устроим им тут театр незаменимого актёра". Ну типа срублю второй семизнак. А тут заказчик решил вдруг со стороны экспертизу заказать, или просто другой знакомый семизнак на код взглянул и выдал - "да вас тут за нос водят, бутерброд из паттернов на ровном месте делают, чтобы никто не разобрался". Что тогда?
заказчик решил вдруг со стороны экспертизу заказать
А что покажет сторонний аудит? А аудит покажет повышение производительности на 30 процентов! )))
Не нравится стиль? Пусть нанимают этого самого тестера или QA, он разберётся или напишет с нуля.. если сможет)
А захотят уволить? А у тебя внезапно накрылся комп и все флешки с документацией полетели, такое иногда бывает.
Потом вместе идут читать контракт, который заключили в самом начале, обязанности и кто кому платит неустойки.

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

Ну т.е. пишется код для вью модели или там расширение для разметки, или спецконтрол, или ещё как-то, который будет через рефлексию вытаскивать данные из атрибутов?
Волшебства тут нет - если что-то запихано в атрибуты, и надо достать, то пиши костыли-портянки. А куда эти портянки поместить - дело десятое.
если что-то запихано в атрибуты, и надо достать, то пиши костыли-портянки.
Не вижу никаких проблем, написал один раз и пользуйся сколько хошь. И не так уж тяжело атрибуты пользовать.
Хочу я глянуть как будете запихивать контролы с валидацией в проперти грид
чтобы не плодить кучи валидирующего кода, а сразу привязать границы
Вообще то вопрос был совершенно для другого. По ответу сразу видно на каком уровне обдумывается зашита/ наступление
- отделение
- взвод
- рота/батарея
- батальон/дивизион
- полк
...
- армия
Вопрос был какого смешивать атрибуты и контролы с ограничениями?
Представьте что есть хотя бы пяток формуляров в котором используются одни и те же данные но в разной форме.
То бишь не всё так однозначно
Вопрос был какого смешивать атрибуты и контролы с ограничениями?
Представьте что есть хотя бы пяток формуляров в котором используются одни и те же данные но в разной форме.
То бишь не всё так однозначно
В чём проблема? В одном случае для каждого привязываемого свойства вы в байндинге будете указывать валидатор. В другом (мой вариант) - привяжете Min и Max к соответствующим свойствам контрола. NumericUpDown юзается везде, где есть числа. Т.е. он подходит для любых чисел, не только с плавающей запятой. И не важно, как и в каком виде он в формуляре. А вот для валидации обычно юзаются валидаторы для каждого типа чисел - типа DoubleValidation, IntValidation и т.п. Хотя, по идее, можно и один громоздкий общий валидатор написать. Но суть в том, что у меня привязки аккуратные и читаемые - Value, Min, Max, а с валидаторами - портяка из многословного XAML с указанием валидаторов для байндингов.
В другом (мой вариант) - привяжете Min и Max к соответствующим свойствам контрола.
Ах вот о чём. Мне как-то тяжело представить что кто-то будет смешивать данные с ограничениями/
Както не хочется видеть подобное, да и SRP тоже не хочет
ACount
ACountMin
ACountMax
Code1
Code1MaxLength
Date
DateFormat
BCount
BCountMin
BCountMax
Ну там полно свойств для чисел со стрелочками вверх-вниз - тот же NumericUpDown. В чём проблема? У этого грида нет свойств Min и Max для чисел? Тогда это грид хреновый.
Основное отличие вашего подхода от моего - у вас либо идёт преобразование данных атрибутов через промежуточную модель (в неё вытаскиваются данные атрибутов), либо через расширения разметки, либо ещё как-то. Т.е. в любом случае - полного медленного кода (рефлексия) для каждого байндинга. А у меня - привязка напрямую к уже готовым свойствам, безо всякой возни с рефлексией, конвертерами и прочим лишним кодом.
Както не хочется видеть подобное, да и SRP тоже не хочет
ACount
ACountMin
ACountMax
Code1
Code1MaxLength
Date
DateFormat
BCount
BCountMin
BCountMax
Наоборот отлично, и уже сгруппировано всё.
А я не хочу видеть портянку атрибутов к каждому свойству. Заметьте, тут они ещё простые - сразу пошли строки задавать. А ведь могли бы начать указывать все параметры атрибутов, как это будет в реальном приложении с мультикультурой и прочим. Тогда для RangeAttribute будет минимум 5 параметров, для DisplayAttribute - минимум 3 (а можно и 5-7), и так далее.
Тогда это грид хреновый
Для начала хорошо бы разобраться в принципе работы проперти грид
https://www.c-sharpcorner.com/article/using-property-grid-...
Наоборот отлично, и уже сгруппировано всё.
Конечно отлично, вместо 4 строчек исключительно данных иметь 10 разного мусора
ACount
Code1
Date
BCount
При этом не зная какие ограничения для чего.
Вот как мне узнать "автоматически", какие ограничения имеет ACount?
как это будет в реальном приложении с мультикультурой
А как это может влиять на количество атрибутов?
Так это для форм? Я с ними сто лет не работал уже.
Ладно-ладно, нравится писать потянки с атрибутами и доставанием данных из них - пожалуйста. Я, поработав так и этак (и подостовав, и просто в обычных свойствах всё похранив), решил, что если как-то не оговорено особо, буду юзать обычные проперти. Для меня это проще, чем обвешиваться костылями разных расширений.
А узнать ограничение на свойство можно как и обычно - посмотрев код. Что в случае с атрибутами, что в моём варианте обычно все данные о свойстве влезут в один экран.
Так это для форм?
Для впф есть тоже самое но изначально, да были винформс
и доставанием данных из них
Доставание может делаться одни единственный раз, а потом просто использоваться.
А узнать ограничение на свойство можно как и обычно - посмотрев код
Разговор то не о человеке, а о машине. Она как то код не может посмотреть
Для меня это проще
А для меня проще - это когда проекту и команде будет проще.
и доставанием данных из нихДоставание может делаться одни единственный раз, а потом просто использоваться.
Ну тогда как я и говорил - вы заводите промежуточную модель для хранения данных атрибутов в виде обычных пропертей. А у меня это сразу так хранится, безо всякого доставания.
Для меня это прощеА для меня проще - это когда проекту и команде будет проще.
А я согласен. Есть люди и команды, привыкшие обвешиваться кучами расширений для всего и уже не мнящие работу без всего этого багажа, забыв, что можно изначально сделать проще. У таких новый проект начинается с подключения десятка разных расширений для атрибутов, разметки, базовых классов для каждой модели с кучей реализованных интерфейсов. Без этого не заводится. Придя в такую команду, придётся подстраиваться, но для себя я делаю по-простому, как я выше объяснял.
вы заводите промежуточную модель
Никто ничего не заводит. Когда надо тогда и берём
А у меня это сразу так хранится
А сколько при этом получается минусов?
Интеллисенсе не пользуете для доступа к данным?
Количество шагов для добавления правила валидации не считали?
А то что все зависимости от модели данных будут считаться измененными - это видимо вообще в расчет не принимается.
что можно изначально сделать проще
Это так кажется с колокольни ефрейтора, как выше уже пытался объяснить.
Придя в такую команду, придётся подстраиваться
Ну это как бы само собой разумеется, работа в команде и работа одиночки совершенно разные вещи.
вы заводите промежуточную модельНикто ничего не заводит. Когда надо тогда и берём
Вы можете привести пример, как вы берёте в той же разметке XAML значение свойства атрибута какого-нибудь свойства модели (не модели представления)?
как вы берёте в той же разметке XAML значение свойства атрибута какого-нибудь свойства модели
Зачем? Валидация делается на других принципах
Зачем валидировать что-то, что пришло из контрола, который в принципе не допустит неправильных данных? Вот есть у вас контрол, где можно ввести числа от 0 до 10, но вы будете ещё дополнительно проверять, а не пришло ли с него чего-то больше 10 или отрицательного?
И ещё - вы данные в каждом слое валидируете?
И где вы показываете все эти error messages, которыми там обильно удобрили все ваши данные? В тултипе? А зачем? Человек должен навести на подсвеченное неправильным поле, дождаться тултипа, прочитать портянку... А если сразу не давать вводить неправильные данные?
[StringLength(50, ErrorMessage = "No more than 50 characters")]
[Display(Name = "Name")]
Зачем вот это "50" и сообщение об ошибке, если можно просто заблочить текстбокс от ввода строк длиннее 50 символов?
Ну и в реальности применение этого атрибута будет выглядеть не так аккуратно, как здесь, а будет обвешано ещё всякими указаниями на ресурсы и ключами в этих словарях. Мы же не на один штатовский рынок работаем, когда все строки можно захардкодить и наплевать на всё остальное, и не аккуратную рекламную писульку делаем, как у него на заглавной странице проекта, а нечто реальное разрабатываем?
Вы, может, не понимаете, но с моей точки зрения, достаточно иметь просто набор нормальных контролов, которые делают все основные валидации для своего типа данных внутри себя. А вам нужно только привязать условия этих валидаций. Таскать данные для валидации между слоями - это ваш метод. Вы своими расширениями из вьюхи лезете в модель через вьюмодель, там на каждый чих дёргается рефлексия с кучей методов и селекторами по имени свойства и прочим параметрам. А потом предъявы к WPF, что это гриды с кучей значений тормозят.
А ещё заметили, что у него там не классический MVVM, а просто модель представления и вьюха. А где основная модель? А как правило именно у основной модели (т.е. модели из области бизнес логики) стоят эти атрибуты. И как он будет прокидывать атрибуты из модели во вью модель?
Блин, да там половины кода для нормальной работы нет! Его пример вообще заведётся в нормально приложении? Где реализация INotifyPropertyChanged?
У чела лысый пример без одного слоя и самого нужного в MVVM интерфейса, а также простейший пример использования атрибутов. В реальности всё будет куда массивнее, запутаннее и некрасивее. Тогда как в моём случае вы просто делаете больше свойств, но используете простейшие привязки и безо всяких портянок, вызывающихся на каждую привязку.
Тут в соседней теме Мурр убивается за 10-15% производительности. А здесь на привязках готов потерять её в разы, как и вы.
Зачем вот это "50" и сообщение об ошибке, если можно просто заблочить текстбокс от ввода строк длиннее 50 символов?
Очень плохо для пользователя. Он не понимает отчего иногда данные можно ввести а иногда нет. Или вот скопировал я данные в поле - А их кто то откусил.
Или вот можно ввести только 5000 символов в сообщение - очень хорошо знать сколько мне еще осталось
И где вы показываете все эти error messages
Как предусмотрено в конкретной реализации
https://docs.telerik.com/devtools/wpf/controls/radcardview...
Могу кстати, поздравить со шнобелевской премией - ещё никто из разработчиков библиотек не додумался делать предлагаемый способ валидации. Может патент еще оформить и всем продавать?
все строки можно захардкодить
Вероятно кто то просто не в курсе как делается локализация текста в атрибутах.
но с моей точки зрения, достаточно иметь просто набор нормальных контролов, которые делают все основные валидации для своего типа данных внутри себя.
Просто не для всех задач подобный подход будет приемлем.
А ещё заметили
не смотрел подробности - десктоп давно не интересует
Зачем вот это "50" и сообщение об ошибке, если можно просто заблочить текстбокс от ввода строк длиннее 50 символов?Очень плохо для пользователя. Он не понимает отчего иногда данные можно ввести а иногда нет. Или вот скопировал я данные в поле - А их кто то откусил.
Или вот можно ввести только 5000 символов в сообщение - очень хорошо знать сколько мне еще осталось
Если что, мой подход и не запрещает вам всё это иметь и показывать. Только костылить с атрибутами и сложными привязками не надо.
Как бы, нормальный контрол как предоставляет возможность привязать границы вводимых данных и отобразить сообщение об ошибке дефолтно, так и приделать что-то своё. Да собственно даже базовые контролы в WPF делают то же самое - рамочку красную кто вокруг рисует, если что-то не так? Сам контрол и рисует. Правда опираясь на значение валидатора.
Как предусмотрено в конкретной реализации
https://docs.telerik.com/devtools/wpf/controls/radcardview...
Кстати, а что, MAUI уже релизнулся? Или это Телерик сами, с нуля свой мультиплатформенный фреймворк накропали? Оно хоть нативное, или опять через браузерный компонент джаваскриптизируют и веб-разметку насилуют?
все строки можно захардкодитьВероятно кто то просто не в курсе как делается локализация текста в атрибутах.
И как же она делается?
Если что, я про то, как будет выглядеть портянка атрибутов, когда туда прикрутят локализацию и всё прочее подобающее, что в реальных приложениях используется. Вы мне говорили, что вам портянка свойств не нравится. А мне не нравится портянка атрибутов, за которым свойств не видно.
но с моей точки зрения, достаточно иметь просто набор нормальных контролов, которые делают все основные валидации для своего типа данных внутри себя.Просто не для всех задач подобный подход будет приемлем.
Ну да, на платформах, где нет нормальных контролов, придётся костылить и лапшекодить.
Зачем валидировать что-то, что пришло из контрола, который в принципе не допустит неправильных данных?
------
Уххх-хухх...
Я и спросил - у вас валидация на каждый слой? И между всеми слоями гуляет модель с атрибутами? И на каждом слое в эту модель лезет портянка с рефлексией вместо обычного чтения свойства Min или Max? Вы точно боретесь за 10-15% производительности?
Зачем валидировать что-то, что пришло из контрола, который в принципе не допустит неправильных данных?
------
Уххх-хухх...
А примеры приводите. ))
А там идёт проходка валидации по всем пропертям атрибута, берётся первая ошибка и выводится. Устранили - снова проходка валидации по всем пропертям атрибута. И так каждый раз. Фигли нам, котонам - 8 ядер, 16 потоков и 64 ГБ оперативы есть у всех, не так ли? Главное, потом тиснуть статейку или на форумах пожаловаться, как проклятый WPF жрёт гигабайт после старта главного окна, а виноват во всём как всегда Билл. ))
Разумеется - нет! Но над другим решением думать надо!!! А у прапорщиков с этим обычно проблемы...
Думать тут как раз особо не надо. Зафигачил всё в атрибуты, загуглил портянку, чтобы из этих атрибутов всё доставать, и впендюрил в свой говнокод. А потом отважно борешься за 10-15% производительности. Если сторонний помидор не увидит, то можно даже за самого крутого альфакодера на фирме сойти. Незаменимый. ))
Могу кстати, поздравить со шнобелевской премией - ещё никто из разработчиков библиотек не додумался делать предлагаемый способ валидации. Может патент еще оформить и всем продавать?
Миллионы мух не могут ошибаться. Толпы скриптизёров, лезущие со своим самым лучшим языком во все щели, не дадут соврать. ))
Тут надо не давить большинством разработчиков, а привести аргументы, почему у нас на атрибутах свет клином сошёлся. Большинство разработчиков легко и быстро перейдут с одного дерьма на другое, или даже с нормальной платформы на дерьмовую, стоит их поманить длинным баксом, а то и просто дать пинка для ускорения. Поматерятся, но перейдут. )
Кстати, а что, MAUI уже релизнулся?Как обещали
https://github.com/dotnet/maui/releases/tag/6.0.312
Всего 13 дней назад, а Телерик уже сварганил пачку контролов для него? Ну как с такими конкурировать, когда у них инсайд? Ты ещё думаешь, пробовать или нет, а у них уже в продакшене. ))
Достаточно просто[DisplayName("My sample text")]--> [Ml_DisplayName(1, "My sample text")]
Какой-то кастомный атрибут, с переписанным интерфейсом доступа к локализованным ресурсам? И так все атрибуты переписаны?
Всего 13 дней назад
А может стоит посмотреть немного больше
- May 10, 2022 - .NET MAUI Release Candidate 3
- April 26, 2022 - .NET MAUI Release Candidate 2
- April 12, 2022 - .NET MAUI Release Candidate - Ready for Cross-Platform App Development
И всё это нужно еще правильно "подключить"
В смысле? Надеюсь, вы не будете привязывать AgeMin к NumericUpDown.Max и наоборот? Как раз с подключением проблемы могут быть в вашем подходе - нужный базовый класс не забыть для каждой модели, в зарметке стиль с тултипчиком для каждой страницы, ещё по мелочам наверняка.
В примере у человека, кстати, по стилю на каждый тип контрола надо добавлять. Т.е. не забыть вставить портянку для каждой новой вьюхи. Ну или через словарь ресурсов, но тогда следить, чтобы стиль не был перезаписан в конкретных вьюхах. А всё почему? Потому что этот подход используется для тупейших контролов - голых текстбоксов, не умеющих ничего, в которые фигачат все подряд типы вводимых данных.
Надеюсь, вы не будете привязывать AgeMin к NumericUpDown.Max и наоборот?
Тоже может быть как и не не то поле. Еще и найти нужно куда привязывать.
Как раз с подключением проблемы могут быть в вашем подходе
Явно опять извращенное понимание действительности.
Кроме добавления атрибута не нужно делать больше ничего
кстати, по стилю на каждый тип контрола надо добавлять
Не нужно работать обезъяной и копировать всё что видно в рабочий проект
Потому что этот подход используется для тупейших контролов
Видимо я зря давал ссылки на дев экспесс и телерик
Какой-то кастомный атрибутЭто было один к одному что тулза делает можно и так
[DisplayName("My sample text")]--> [DisplayName(Translate(1, "My sample text"))]
Что за тулза? Чего вы всё время недоговариваете? )))
У вас кастомный атрибут с делегатов в параметрах конструктора?
У меня всё честно и открыто - вот список пропертей, вот контролы. Привязываем просто и без дополнительных костылей. А у некоторых помидоры примерно так объясняют, как работает их новый фреймворк.
А интеллисенсе куда завернем?
А сколько всего нужно дописать чтобы добавить новое правило?
Куда заворачивать, какое правило? Вы чего?
MyField
MyFieldMin
MyFieldMax
NumericUpDown
Value={Binding MyField}
Min={Binding MyFieldMin}
Max={Binding MyFieldMax}
Всё. Не надо никаких сообщений об ошибке, не надо подсветок, не надо валидирующих правил, не надо конвертеров, не надо реализаций дополнительных интерфейсов, не надо тормозов с выполнением портянки с рефлексией НЕСКОЛКЬО РАЗ на каждое срабатывания привязки. Ведь если привязка прошла валидацию, значит для всех свойств всех атрибутов каждого свойства выполнилась эта портянка. И это происходит на каждое срабатывание байндинга, повторюсь. Вы курсор в поле ткнули, символ ввели, а у вас уже куча событий произошла. И часто байндинг по 2-3 раза лишь за эти короткие действия срабатывает. Дарю Мурру идею - меняем ваш подход на мой и пишем в заслугах - ускорил прогу в 30 раз.
Всё это отобразится интеллисенсе из коробки.
Ваш юзер, который спросит, а чего это я не могу больше и меньше определённых значений ввести - он и вашим сообщениям об ошибке возмутится. Хочу мол ввести и всё тут.
Но если прямо хочется дать инфу юзеру, в каких диапазонах вводить, то лучше это делать не после ввода во всплывающем тултипе (самый дурацкий, тормозной и раздражающий способ), а сразу дать понять перед вводом, в каких диапазонах будет валидное значение. Я иногда делаю такой лейбл перед полем ввода:
DisplayName = $"{MyFieldName} ({MyFieldMin} - {MyFieldMax}):"
TextBlock Text={Binding DisplayName}
Т.е. лейбл будет выглядеть примерно так:
Параметр (0-100):
Тут я сразу вижу, что и сколько могу ввести, а не пишу наугад, жду тормозной тултип и вчитываюсь в мелкий серый текст на белом фоне (дефолтный стиль для тултипов), который ещё и через 5 секунд исчезает автоматически.
Кроме добавления атрибута не нужно делать больше ничего
С какой стати? А лапшу в вашем же примере кто будет писать, как и наследовать все модели от базового класса с этой лапшой? А во вью модель из модели как перетаскивать эти атрибуты? А сериализация? Где весь обслуживающий код для задач реального приложения?
Мой подход - представьте себе мир безо всей этой муры.
Куда заворачивать, какое правило? Вы чего?
Очень ломит объяснять всё в подробностях как первокласснику.
Validation rule - так понятнее?
Нужно добавить минимум (1)
MyFieldMin
MyFieldMax
При этом кто как будет называть суффиксы для других правил и какие вообще правила существуют дело темное.
и (2) При этом во все формы которые еще нужно найти. Как уже говорил, ошибки ввода попадаются
Min={Binding MyFieldMin}
Max={Binding MyFieldMax}
Не надо никаких сообщений об ошибке, не надо подсветок, не надо валидирующих правил
Не надо рассматривать какой то конкретный случай и рекламировать его как золотую пулю. Не кажется странным, что все остальные такие тупые и до подобного метода никак не додумались?
Когда то действительно хорошо без ошибок, типа в цифровое поле поле вводить только цифры.
жду тормозной тултип
Если кто то делает сообщения об ошибке в тултипе то это не означает что так делают все.
Важна именно система. И для системы ручные проперти никак не подходят.
А лапшу в вашем же примере кто будет писать, как и наследовать все модели от базового класса с этой лапшой?
Не нужно думать только в одном направлении.
Система пишется/покупается один раз а после только используется.
А сериализация?
А в чем проблемы сериализации данных? Хот и не вижу смысла делать это для UI модели.
Как раз то в вашем подходе будет очень много мусора.
Мой подход
Да пожалуйста, делайте сколько хотите, главное чтобы подальше от нас было.
При этом кто как будет называть суффиксы для других правил и какие вообще правила существуют дело темное.
А атрибуты валидации у вас стандартизированы, чтоли? Только если вы прикажете по фирме не использовать что-то не из установленного набора. Есть МСовская поставка, и есть куча сторонних, плюс самописные.
Покажите мне, кто не понимает, что такое Min и Max. А ещё есть люди, которые не знают, что означает префикс подчёркивания перед полем. Да мало ли кто каких соглашений не знает. Придёт на фирму - узнает, как на этой фирме делается. Т.е. это не проблема.
Не кажется странным, что все остальные такие тупые и до подобного метода никак не додумались?
Не кажется. Поэтому и придумали контролы типа NumericUpDown со свойствами Min и Max, и тому подобные. Я же их не от фонаря в пример приводил.
и (2) При этом во все формы которые еще нужно найти
Ctrl+Shift+F, ограничение по типу файлов .xaml - и вот вам все упоминания свойства.
Как уже говорил, ошибки ввода попадаются
Типа когда минимум максимуму присвоил или наоборот? Приводить в качестве минуса мисклик какого-нибудь программиста - передёргивание. Вы и в атрибуте можете минимум с максимумом перепутать. До выполнения кода ничего мне не мешает написать так
[Range(2.0, 1.0)]
Только после выполнения у вас сработает валидация и вывалится исключение. У меня Студия 2019 для .NET 5 не показывает ошибок при компиляции.
Единственное, с чем могу согласиться - атрибуты валидации это уже готовая валидация. Вам не надо писать свой код. А в моём случае надо написать самому проверку попадания значения между свойствами Min и Max. Но как я уже писал, если применять правильные контролы и изначально не допускать приход неверных значений, то можно и без этой проверки обойтись.
С другой стороны, атрибутами все случаи не покроешь. Поэтому у вас будет частично атрибутная валидация, частично кастомная - либо дополнительные проверки в реализации IDataErrorInfo, либо самописный атрибут.
И отчего бы не написать просто так?
NumericUpDown
Value={Binding MyField}
Min=0
Max=10
А что мешает так написать?
[Range(10, 1000, ErrorMessage = "Все оно, а я конфетка!")]
В вашем случае надо не забыть реализовать IDataErrorInfo (или отнаследоваться от базового класса с его реализацией), прикрутить стили с сообщениями об ошибках, и так - на каждую модель. Вобщем, в вашем случае целый список, что нужно сделать. А вы мне говорите, что человек забудет привязать границы и захардкодит их.
Вы просто не open minded и не пробовали сделать, как я говорю. А я пробовал и так, и так. И возьба с атрибутами меня не вдохновляет. Пока не будет нормального простого интерфейса для вытаскивания данных из них, а не портянки с рефлексией и указанием кучи данных из перечислений по типам свойств (ещё поди разберись, какие сочетания правильные).
Вы так и не сказали, как будете атрибуты модели прокидывать во вью модель.
А вообще, валидация пользовательского ввода должна быть максимально жёсткой. Т.е. нужно не валидировать постфактум, а вообще не давать пользователю вводить неправильные данные. Держать его, так сказать, в ежовых руковицах. Ну это как банкоматы - тупые и железные, с железными кнопками, чтобы ничего не сломалось. Максимально ограничить свободный ввод. По-возможности давать выбирать лишь из готовых выпадающих значений. В банкоматах можно вводить лишь цифры и несколько знаков. Никаких печатаний "Kontostand" и тому подобного вручную - только выбор из предлагаемого меню, тыкание цифры.
Вот есть на экране одна кнопка "Сделай мне круто!". Её можно нажать, а можно не нажимать. Валидация простейшая - её тупо нет. Что может пойти не так?
Validation rule - так понятнее?
-----
Не-не, надо сделать... правильно...
Мин и Мах - это - не правильно! Это всего один регион!
Надо нарисовать произвольное количество регионов в которое может входить значение!!!
Для начала - штук 200... т.е. дописываем 400 полей для одного поля данных и думаем над проблемой как их добавить в ран-тайме!
Т.е. это не проблема.
ну вот как назвать поле в котором список разрешенных символов для контрола?
А атрибуты валидации
А атрибуты вываливаются по подсказке и после выбора атрибута сразу известны его параметры.
Поэтому и придумали контролы типа NumericUpDown со свойствами Min и Max
А проперти для связи с ними хто придумаль?
Ctrl+Shift+F
А зачем вообще что то искать? Да и что именно?
Приводить в качестве минуса мисклик какого-нибудь программиста - передёргивание.
вообще то это минусы дополнительной работы.
В вашем случае надо не забыть
Блин, ну ничего не надо делать каждый раз для новой формы. Один раз делается и потом только используется.
Вы так и не сказали, как будете атрибуты модели прокидывать во вью модель.
Это пусть рассказывает тот, кто считает, что это нужно делать
Вы так и не сказали, как будете атрибуты модели прокидывать во вью модель.Это пусть рассказывает тот, кто считает, что это нужно делать
Как вы будете в этом коде доставать атрибуты модели, если класс - во вью модели? Варианты есть - один другого лапшекодинговее, но меня интересует, как именно вы будете это делать.
доставать атрибуты модели
Вообще то нет интереса и времени писать код согласно требований.
Как пример, которому не обязательно нужно подражать
https://www.codeproject.com/Articles/97564/Attributes-base...
http://danielvistisen.com/validate-using-attributes-in-mvv...
И даже немного по другому
https://www.engineeringsolutions.de/validation-in-mvvm/
https://stackoverflow.com/questions/19498485/proper-valida...
Вы, похоже, не понимаете, что я имею ввиду. Все ваши примеры - это валидация на стороне вью модели. А атрибуты обычно устанавливают для модели. По всем вашим ссылкам авторы пишут MVVM, но модель куда-то у них подевалась.
Вот классическая статья от одного из первых авторов по WPF и MVVM, и в этой идее валидации изначально была реализация IDataErrorInfo в обоих слоях (модель и вью модель), при этом на каждом своя валидация. Обратите внимание на объект _person там - это переменная для хранения модели во воью модели. При присваивании свойству Age вью модели значения, сначала проходит валидация вью модели, затем идёт присвоение свойства модели, и там происходит своя валидация. По вашим ссылкам авторы всё упростили и извратили, забыв про модель - а нафига она им вообще нужна тогда? Ваши авторы фигачат атрибуты прямо для вью модели и называют это MVVM. С таких подходом им не нужна модель. Ну или роль модели у них выполняет вью модель. Так тоже можно, но это не MVVM. А они просто засоряют мозги неадекватными названиями себе и другим.
Для такой валидации как в ваших статьях, вам нужно кинуть ссылку на модель в базовый класс вью модели, где у вас реализован интерфейс IDataErrorInfo и где проходит валидация. А так как модель может быть любым типом, надо делать базовый класс дженериком, и чтобы параметр типа этого дженерика реализовывал какой-то валидирующий интерфейс, и это будет не IDataErrorInfo, а что-то с методом Validate - чтобы чтобы однообразно вызывать валидацию модели для любого типа модели. Без базового класса вы будете писать портянки валидации для каждого класса отдельно. В результате что в ваших примерах, только реальных, а не висящих в воздухе, что в подходе Джоша Смита - куча лапшы, переусложнённые модели (и вью модели) с параметрами типов. А в ваших примерах, в отличие от Джоша Смита, ещё и рефлексия вовсю дёргается.
А в моём подходе вы всё храните в свойствах, пробрасываете свойства модели во вью модель сразу, без преобразований, вам не нужен никакой интерфейс, вам не нужна базовая модель с валидацией, вы не испольузете дженерики, а вы сразу привязываете свойства и их ограничения к правильным контролам. И даже если вы не используете MVVM по факту, а всё делаете в одной модели, то хранить все ограничения в свойствах тоже лучше, чем в атрибутах.
Где-то надо использовать и атрибуты, но явно не в формошлёпстве с вышеописанными переусложнениями. IDataErrorInfo - это усторевший в формошлёпстве многословный интерфейс, как и всякие портянки валидирующих правил в разметке. Можно обойтись и без всего этого, если применять правильные инструменты.
Другое дело, если у вас приложение куда более сложное, чем три слоя MVVM, или MVC, или MVP. Тогда, возможно, вам стоит держать что-то в атрибутах, делать валидацию на каждом слое (мы не доверяем данным, передаваемым между слоями, например) и т.п. Но тут, где просто MVVM, писать такие простыни и реализовывать громоздкий IDataErrorInfo - это оверхеад. При этом ещё и упрощать во всех примерах M-V-VM до банального V-VM. Во втором случае вообще непонятно, нахрена все эти портянки.
Ещё я иногда для модели использовал атрибуты, но во вью модели доставал из них значения и сохранял в свойствах, которые и привязывал к контролам. Т.е. валидацию не использовал, а атрибуты использовал лишь как контейнеры для хранения валидационных данных. Точнее, валидация происходила в самих контролах.
Главное, не забыть, что это лишь один из подходов, и в случае возвращения к валидации через атрибуты непосредственно, не забыть реализовать интерфейс IDataErrorInfo, т.к. сами атрибуты ничего не валидируют. Я вот забыл и недоумевал потом - а чего это сообщений об ошибках нет, хотя в атрибутах всё установлено.
авторы пишут MVVM, но модель куда-то у них подевалась.
Вообще то хорошо бы вначале немного почитать о MVVM паттерне
https://stackoverflow.com/questions/3372939/is-it-ok-to-ha...
https://docs.microsoft.com/en-us/archive/msdn-magazine/200...
А после рассказать как будем обходится без сообщений в данном случае (И какие проперти будем добавлять?)
Можно обойтись и без всего этого, если применять правильные инструменты.
Безусловно, зачем нам эта тормознутая студия, когда в notepade всё так просто
А после рассказать как будем обходится без сообщений в данном случае (И какие проперти будем добавлять?)
Я тоже могу сказать, что не надо воспринимать всё и всегда буквально. В частности, эта картинка для дебилов - ну вдруг найдутся люди, которые не понимают, а чего это кнопка "Save" не нажимается, если я все поля пустыми оставляю. Написано тут всё лишь для иллюстрации, как можно использовать валидацию. А можно было бы не писать под каждым полем свой текст, а написать один общий для всей модели - "все поля должны быть заполнены". Или "обязательные для заполнения поля отмечены звёздочкой". И такой текст может быть вообще общим для всех моделей приложения, поэтому его можно затолкать в общие локализованные ресурсы под одним ключём. И эта одна запись - всё, что нужно будет для сообщений валидации во всём проекте.
Но можно, конечно, и выписывать простыни пояснений под каждым полем.
Я предлагал другой вариант - рядом с названием поля в скобках или ещё как писать, какой диапазон, какая длина строки позволены и прочее. Т.е. чтобы сразу видел пользователь, что можно, а что нельзя. И эту инфу можно положить в виде обычного свойства рядом с тем свойством, которое оно описывает.
Стремление всё затолкать в атрибуты - это такая детская болезнь максимально заюзать все новые модные фичи. Даже там, где они лишние. Вот например есть атрубит Display, где отображается свойство DisplayName. Почему это не может быть дополнительным свойством? - Может. У того же Джоша Смита в старых статьях по MVVM это и отображено в обычном свойстве. Но кому-то надо обязательно всё в атрибуты запихать.
Обычные свойства и атрибуты - суть одно и тоже. И там, и там хранятся какие-то данные, мы их достаём. Только с атрибутами работать сложнее и медленнее по производительности. А ещё они требуют громождения вокруг себя инфраструктуры.
Вот зачем вам, например, свойства объекта выписывать, если можно навешать атрибутов TypeProperty над объявлением класса и всё?
Или другой пример - перечисления. Можно навешать кучку атрибутов над каждым элементом перечисления - язык это позволяет сделать. А можно написать класс, где будет храниться свойство с перечислением и данные, которые раньше были в атрибутах, только теперь в виде свойств. Вам какой подход больше нравится:
enum Rarity { [Display(...)] [Properties(Prop1 = ..., Prop2 = ..., ...)] Common, [Display(...)] [Properties(Prop1 = ..., Prop2 = ..., ...)] Uncommon, ... } class Rarity { Rarity Rarity { get; set; } // здесь это другое перечисление - без атрибутов string Name { get; set; } string DisplayName { get; set; } ... Prop1 { get; set; } ... Prop2 { get; set; } ... }
чего это кнопка "Save" не нажимается
Я тоже могу сказать, что не надо воспринимать всё и всегда буквально
Не обязательно всё поля должны быть пустыми и на смартфоне обычно поля не помещаются все на экран.
А подобный вопрос пользователи задают очень часто. Помню был на нескольких сайтах,. а фиг его знает отчего дальше не пускает. Так и ушел.
И такой текст может быть вообще общим для всех моделей приложения
Страшно хочу увидеть общий текст для этого диалога
Стремление всё затолкать в атрибуты - это такая
А стремление затолкать всё в свойства это тогда что?
Вот например есть атрубит Display, где отображается свойство DisplayName. Почему это не может быть дополнительным свойством?
У меня приличных слов просто
уже не хватает.
Кричать о модели и заявлять подобное...
Обычные свойства и атрибуты - суть одно и тоже
Я не могу это уже комментировать - мурка ты где?
А можно данный пример с готовым кодом?
А то болтать можно долго и нудно о преимуществе пропертей.
Очень интересует связка и заполнение между Rarity.Common и Rarity.DisplayName допустим при реализации комбобокса
https://brianlagunas.com/localize-enum-descriptions-in-wpf...
...
Нашел похоже http://oopbase.de/posts/localizing-enum-values-in-an-enter...
На какой вариант будет кричать ура! мой!
А это немедленно в Лувр - как самое удачное решение - сокровищница мирового искусства программирования
new UserModel(Gender.Female, "Anna"),
new UserModel(Gender.Male, "Scott")
Очень интересует связка и заполнение между Rarity.Common и Rarity.DisplayName допустим при реализации комбобокса
https://brianlagunas.com/localize-enum-descriptions-in-wpf...
...
Нашел похоже http://oopbase.de/posts/localizing-enum-values-in-an-enter...
Когда Rarity это класс, то надо где-то создать коллекцию объектов этого типа - тогда будет полное соответствие enum Rarity.
Чего это челы по вашим ссылкам изобретают велосипеды, когда уже давно есть готовый описательный атрибут с локализацией в Дотнете? И он там лет 10, наверное, уже есть. Минимум.
https://docs.microsoft.com/en-us/dotnet/api/system.compone...
Странная ошибка - при редактировании есть после сохранения нет. Перезаписал.
У меня так тоже бывает.
Вы же сами видите, что на форме просто куча лишней и дублирующей информации (типа диапазона для возраста - и в названии поля, и в сообщении об ошибке). Для такой формы достаточно "поля со звёздочкой обязательны для заполнения".
Ещё интересно, что как раз, как я советовал, в названиях полей указаны допустимые интервалы и прочие подсказки. Человеку не интересно играть в вопрос-ответ с машиной. Его дико раздражает, когда очевидный фидбек приходит лишь после неправильных данных. Так же его раздражает читать портянку, написанную красным шрифтом. Всю эту писанину можно опустить, и оставить одну надпись, как я сказал и звёздочки. А ввести возраст вне диапазона поможет контрол, который просто не может принимать значения вне диапазона (офигеть рокет сайенс!). Валидация тогда будет проходить внутри контрола, без обращения к другим слоям. Причём валидация будет молчаливой - безо всякой красной мазни, знаков восклицания и красных портянок. А если кто-то не понимает, что "Пароль" и "Повторите пароль" должны совпадать, а "Возраст (от 18 до 70)" не позволяет ввести вне этого диапазона, то ему явно не нужно пользоваться вашим сервисом. Таким людям нужен помощник. Ну мало ли что, разные люди бывают - деменция там старческая, принципиальная жизненная позиция нигде и никогда не повторять пароли, ещё чего.
С паролем согласен - что-то нужно придумать. Скорее всего, тут нужна валидация (не обязательно в атрибутах). Можно, конечно, забайндить второе поле на первое, и проверять равность. Лучше, если это тоже всё будет внутри специального контрола инкапсулировано, чтобы не городить проверки в конвертерах, в модели или ещё где.
А как вы сделаете атрибутную валидацию повтора пароля? Ну чтобы добавил атрибут, типа [ConfirmationRequired], и всё само завертелось, без правки реализации IDataErrorInfo.
А как вы сделаете атрибутную валидацию повтора пароля?
точно также как и всё остальное
public string Password1 {get; set;}
[MustBeEqualValue(nameof(Password1), ErrorMessage="Two passwords must be equal")]
public string Password2 {get; set;}
...
var property = validationContext.ObjectType.GetProperty(_comparisonPropertyName); comparisonValue =(xxx)property.GetValue(validationContext.ObjectInstance) if (currentValue > comparisonValue) return new ValidationResult(ErrorMessage); return ValidationResult.Success;
Вот всю эту муру лучше бы внутри какого-то спецконтрола иметь. Я был бы не против атрибутов, если бы все портянки по работе с ними делались под капотом, автоматически и без моего вмешательства. А реализации каких-то дополнительных интерфейсов, возня с рефлексией - нафиг мне это надо? Я в атрибутах указал - пусть само берёт оттуда и валидирует.
В проектах ASP.NET MVC как-то это делается - там вы руками ничего не валидируете, интерфейсы не реализуете, а лишь прописываете атрибуты. Весь код валидации существует где-то в других библиотеках, о которых я могу даже не знать. Т.е. атрибуты там работают из коробки, а не конструктор "сделай сам".
все портянки по работе с ними делались под капотом, автоматически и без моего вмешательства
Ну после первого использования или создания либы так и происходит.
Если либы не нравится делать то это уже другая проблема.
По крайней мере, микрософту этот концепт нравится.
Почему в ASP.NET MVC смогли не парить мне мозги, а в других местах с этими же атрибутами нужна какая-то возня?
Не просто библиотеку заюзать, а как минимум указать ещё базовый класс с реализацией интерфейса. В ASP.NET MVC ничего не надо указывать и наследовать - прилепил атрибут, и он работает. Именно этого я от них и ожидаю. Я уже написал в атрибуте, что я хочу от модели. Даже сообщения об ошибках указал. Почему я должен снова сам в них внутрь лазить?
Просто команда ASP.NET MVC смогла накатать либку для автоматической валидации через атрибуты, а команда WPF забила. Она много на что забила. Да и МС сама на WPF давно забила.
Интересно, во всяких Blazor и MAUI тоже всё надо вручную делать, или они как-то подумали о разработчиках?..
Да и МС сама на WPF давно забила
А кто на впф еще не забил? Только те кому десктоп еще нужен.
во всяких Blazor
Да и МС сама на WPF давно забилаА кто на впф еще не забил? Только те кому десктоп еще нужен.
Только МС забила на ВПФ ещё лет 10 назад.
во всяких Blazorhttps://blazor-university.com/forms/validation/
Вот видите, как здорово - не надо врукопашную реализовывать всякие IDataErrorInfo. Прямо как в Razor Pages в ASP.NET MVC. Могут же, когда хотят.
Мне, пожалуйста, такое же в WPF, MAUI и остальных UI-фреймворках заверните.
А кто на впф еще не забил?
-----
Ну меня на последнем интервью спрашивали на предмет есть ли в активе...
Меня всё беспокоит эта ситуация. Вот добился ты типа всего, на Панамере по всяким деревням Гадюкино разъезжаешь... А всё равно как обычный рядовой Васян на поклон ко всяким девочкам-припевочкам на ресепшене ходишь. Я же себе на семи знаках это примерно так представлял:
Сидишь такой на террасе своего домика во Флориде, тебе звонит твой знакомый по прежним проектам и бизнесу - мол, хай, Алекс, не хочешь заработать лишний миллион? Я - почему бы нет. Что надо делать? - Да есть тут один проект. Надо его подшаманить. Серьёзные дяди деньги теряют, но хорошо заплатят, если успеешь быстро и качественно сделать. Сам понимаешь, вокруг одни идиоты, а таких как ты, семизнаков, мало. Выручай, брат! Бонусом пачка растущих акций впридачу. Ну ты такой конечно не отказываешь старому партнёру в услуге, тем более хорошо оплачиваемой. - No problemo, чувак. Но я ставлю свои сроки и хочу два миллиона. И плюс обязательные пончики с банановым кремом из одной нью-йоркской пекарни чтобы мне каждый день по спецзаказу подвозили - люблю я их. Запомни - свежие, из одной пекарни и именно с банановым - не вишнёвым. Это обязательное условие!
Только МС забила на ВПФ ещё лет 10 назад.
Ну не полностью
Сколько я этих планов видел. Вся эта поддержка - чисто для поддержания штанов старой технологии. Нового - ничего. Ну оно и понятно - сейчас у МС другие планы. Но 10-то лет назад такая же "поддержка" была - т.е. вообще голяк. После .NET Framework 3.5 на WPF считай забили.
Блин, снова эта валидация всплывает. Встречаю в коде такую лапшу:
- проверка, не пустое ли введённое значение - если пустое, то пишем сообщение об ошибке (типа "введите число");
- проверка через эксепшены, парсится ли введённое значение (типа метода int.Parse), и если нет - пишем сообщение об ошибке (типа "введите целое число");
- если парсится, то проверяем на неотрицательность числа - если отрицательное, то пишем сообщение об ошибке (типа "введённое число должно быть неотрицательным").
Вся эта лапша на десятки, если не сотни строк кода, куча сообщений об ошибках на все вкусы. Ещё и вся эта хрень логируется (ввёл пользователь отрицательное число - СРОЧНО В ЛОГ!) Я ещё удивился, а что так мало проверок и сообщений? Почему не минимум десять, например?
Мой вариант - пишем рядом с полем подсказку типа "значение должно быть целым неотрицательным" или ещё проще - диапазон (0 - 200) и дизейблим зависимые контролы, пока пользователь не введёт правильное число. И больше не пишем никаких сообщений об ошибках. Когда введёт правильное - енейблим контролы. ВСЁ! Проверки по сути те же самые, что и в первом варианте, с той лишь разницей, что мы не грузим пользователя бесконечными сообщениями на каждый неверный шажок и не лапшекодим менеджент всех этих сообщений. Разница в читаемости кода и понятности в разы... Единственный минус, что пользователи-олигофрены могут не понять - как это, мол, "введите целое неотрицательное число"? Поподробнее можно? Давайте я буду вводить буквы и знаки, а вы на каждый введённый символ мне кучку сообщений выдавать, чтобы я знал, где ошибся?
Я, конечно, понимаю, что некоторым прикольно сидеть и лапшекодить сотни строк на всю эту муйню - целый день был занят, один контрол закодил. И обязательно пачку юнит-тестов! А вто вдруг какое-то сообщение из десятка пропустил. И вот у нас пять экранов кода, которые делают, по сути, никуя, кроме как толкут воду в ступе... Смотрю на свой текущий проект - если весь этот олигофренский подход убрать и переписать, кодовая база на порядок уменьшится. Правда, команда тогда не получит по семь знаков на рыло (а фигли - серьёзный проект делали несколько лет индусским лапшекодом!) и не отъедет всем кагалом на пенсию в Майами. ))
Да, про валидацию...
Заполнил сегодня форму.
Кликнул Сабмит...
Вылезла следующая валидация:
There is an error with this candidate:
Missing required field:
никаких других пометок нет.
Посмотрел - все заполнено.
Подумал, поменял в паре мест нолик на единичку... и все пошло...
А ты говоришь - валидация, много писанины...
никаких других пометок нет.Посмотрел - все заполнено.
Подумал, поменял в паре мест нолик на единичку... и все пошло...
А ты говоришь - валидация, много писанины...
Ситуации разные бывают, когда тебе надо к примеру зарегистрировать машину, будешь вокруг компьютера вытанцовывать,
меняя нолики на единички, дополняя ноликами короткие номера, тк обрезают, а валидацию короткий не проходит итп итд.
пока не добьёшься не успокоишься... в худшем случае прозвон по телефону, на фирме девочки заносят данные от руки...
***
А теперь представим, ненапряжённую ситуацию, когда люди приходят добровольно, например рекламную акция - регистрация...
компания вбухивает мильёны денег в рекламу, проводит кучу праздников, - а люди почему то на странице не регистрируются???
пияр-манагер не понимает, никто не понимает... а всё потому-что новенький джуниор "почистил бесполезный мусор в коде"
и никаких ошибок система не выдаёт, логи не ведёт, МЕТРИКИ самое главное в этом бардаке тоже нет, чтоб исправить ошибку!
***
Это напоминает мне тему, где джунам всёравно точка или запятая, а людям в офисе разгребать лишние проблемы, с сортировкой:
https://foren.germany.ru/programmer/f/39534706.html#Post39...

И так - по всем 200+ полям на форме...
А когда осилишь - тебе еще с полсотни связанных таблиц кинут...
И так - с каждой формой.
Формы, где в каждой по полста связанных таблиц? - Неудивительно, что юзеры делают ошибки и не могут нормально заполнить такую форму. Надо 200 таблиц делать, чтобы наверняка!
Для полей вида "введите число" или "введите строку" можно, наверное, сделать простую подсказку (не всплывающую, а сразу возле лейбла) типа диапазона вводимых чисел или длину строки со списком исключённых символов?
Вылезла следующая валидация:
There is an error with this candidate:
Missing required field:
Поди, сообщение где-то в конце формы - типа, все сообщения валидации пишутся не напротив конкретного поля, а где-нибудь обособленно, на уровне формы. Тоже так себе подход.
Вы сейчас описываете банальные баги. Причём тут мой подход и баги вообще? Такие баги могут быть при любом подходе. Это не дискредитирует конкретно мой подход.
А теперь представим, ненапряжённую ситуацию, когда люди приходят добровольно, например рекламную акция - регистрация...
компания вбухивает мильёны денег в рекламу, проводит кучу праздников, - а люди почему то на странице не регистрируются???
пияр-манагер не понимает, никто не понимает... а всё потому-что новенький джуниор "почистил бесполезный мусор в коде"
и никаких ошибок система не выдаёт, логи не ведёт, МЕТРИКИ самое главное в этом бардаке тоже нет, чтоб исправить ошибку!
Гораздо круче, когда логов и метрик - вагон и тележка, но разобраться и понять из этого всё равно ничего нельзя. Зато диски логами забиты. Ну ты их конечно подчищаешь, убивая предыдущую статистику и всю суть подробного логирования...
когда логов и метрик - вагон и тележка, но разобраться и понять из этого всё равно ничего нельзя. Зато диски логами забиты. Ну ты их конечно подчищаешь, убивая предыдущую статистику и всю суть подробного логирования.
Ты за место на дисках не переживай, подключат ещё несколько штук или даже несколько шкафов. Информация и есть конечный продукт, за это платят деньги.
А вот анализ ошибок и всего остального могут не в ручном режиме, а специальными инструментами проводить, могут даже нейронную сеть задействовать, не?

А блокчейн?
"Due to the protocol changes of Ethereum: Rinkeby, Ropsten and Kovan test networks may not work as reliably and will be deprecated soon.
The Rinkeby testnet explorer has been discontinued and set to read-only on October 5th, 2022. Please migrate your contracts and deploy new ones on Goerli or Sepolia."
кароче, я в процессе переезда!

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

Вот сейчас типичный кейс валидации встретил, и какой-то странный. Запросили с сервера таблицу и показали юзеру на клиенте. Естественно, клиенту передали набор данных с айдишниками в БД, но в UI их не показываем - т.е. айди не редактируемый. Юзер хочет удалить одно данное. Что делает старый код, который я переписываю - он берёт айдишник выбранного для удаления элемента, делает запрос в БД - есть ли с таким айдишником объект. Если есть, достаёт этот объект, читает его айдишник и передаёт в запрос на удаление на сервер. Получается, что айдишник, который хранится в наборе данных, показанных клиенту, не используется для отправки на удаление на сервер. Это что-то типа валидации - проверка, есть ли такой айдишник в БД? Типа, на клиенте кто-то подменил набор, переданный изначально с сервера?
По-моему, это чушь и лишние запросы в БД. Если так уж не доверяете клиенту, что считаете, что он может нередактируемый айди подменить, то валидация явно должна быть не через запрос в БД. Просто при попытке удалить несуществующий айди будет исключение на сервере, которое передают клиенту, но смысл делать попытку отдельного запроса и доставания целого объекта, чтобы потом просто считать его айди и передать в запрос на удаление?
А главное, если айди существует, то при его подмене будет просто удалён другой объект. Но с точки зрения текущей валидации это норма... Бред какой-то! Ну и ещё главное - софт работает в закрытом виде на территории предприятия, в интранете, и наружу доступа нет. Подменить нередактируемый айди могут
лишь агенты госдепа работники, которые как-то взломали программу. Защита от такого взлома явно не этим тупым запросом с доставанием объекта делается. Остаётся одно - говно- и лапшекод, когда чел, его написавший, сам не понимал, что и зачем там происходит. Тут даже на самописный фреймворк не спишешь, т.к. даже по логике этого фреймворка написанный код делает какую-то лютую дичь.
Говоре же - гении делали. Там весь многосотстрочный говнокод можно на порядок ужать.
Типа, на клиенте кто-то подменил набор, переданный изначально с сервера?
Проверка лишняя, но понять можно. Пока мы смотрим на данные, другой пользователь может их уже удалить.
Просто, тоже самое может произойти и после валидации. Только временное окно будет меньше.
Да я не против, чтобы другой удалил. Но тогда будет исключение фреймворка, работающего с БД - его и будем обрабатывать и показывать - типа объекта в БД нет. Мне непонятно, почему автор кода пытается вытащить полноценный объект из БД, а потом прочитать его айдишник и затем по этому айдишнику удалить. Лишняя операция. Объект могут удалить между его чтением и его удалением по его айдишнику - и опять будет та же ошибка - по такому айди объекта нет. Смысла делать промежуточный запрос нет.
А как интересно он его пытается вытащить?
Я же говорил - из готового списка объектов в гуе, в котором хранится в том числе айди этого объекта в БД, берётся выбранный для удаления объект, читается его айди, по этому айди вытаскивается этот же объект из БД, читается айди вытащенного, даётся команда на удаление объекта по этому айди. А чё только два раза? Можно же было в цикле раз десять повытаскивать и посчитывать, и только потом удалить?
На проверку наличия перед удалением, как я сказал, не похоже - удалить могут в процессе проверки, т.к. она происходит в серверной части приложения, а не в самой БД. Да и в самой БД это явно не атомарная операция. И смысла в такой проверке нет, т.к. всё и так в трай-кэтч завёрнуто, так что ошибка ненахождения по айди при удалении такая же, как ненахождения по айди при запросе объекта.
Что делает старый код, который я переписываю - он берёт айдишник выбранного для удаления элемента, делает запрос в БД - есть ли с таким айдишником объект. Если есть, достаёт этот объект, читает его айдишник и передаёт в запрос на удаление на сервер. Получается, что айдишник, который хранится в наборе данных, показанных клиенту, не используется для отправки на удаление на сервер. Это что-то типа валидации - проверка, есть ли такой айдишник в БД?
Я бы сказал, что это не валидация, а оптимизация.
Подозреваю, что DELETE - довольно медленная операция (как минимум из-за того, что на время удаления надо блокировать БД), поэтому для того, чтобы снизить нагрузку на БД решили встроить дополнительную проверку и удалять только те строки, которые реально существуют.
Тут конечно встрает вопрос - удаляют ли строки достаточно часто, чтобы эта проверка иммела смысл. В принципе ты можешь легко проверить это предположение - сделай цикл из 10К итераций и замерь время выполнения до твоей оптимизации и после.
Возможно также этот код был написан для какой-нибудь старой версии БД, в которой была проблема с удалением несуществующих ключей.
Написано было для старой версии, но MS SQL Server. Далее, удаляются юзеры - для них явно скоростного и частого удаления не требуется.
Какая ошибка - не знаю, не пробовал пока юзеров удалять.
Да там всё проще, похоже. Я думаю, как и всё в этом древнючем приложении, тут не только "гении" чудили, но и код через десятые руки прошёл, где каждый подшаманил что-то своё, не сильно вникая. "Работает же? - Работает... А то, что через задницу - не моё дело, у меня на таску 15 минут." Что-то типа такого, наверное.
только "гении" чудили
Чтобы понять, как решить проблему, ты должен думать как проблема, жить как проблема, ты сам должен стать проблемой!

Давай по чесноку, тебе больше всех надо? Мир улучшить он решил, щас как перепишет код десятилетиями копили, производство фабрики встанет...

Я был на двух фабриках в двух разных городах. На одной всё автоматизировано и товары перевозятся тележками-роботами по складам и цехам. На другой на приёме, обработке и перевозке товаров работают люди с помощью этой программы, в которой надо проверять человеческий ввод и прочие поблажки кожаным мешкам делать.
товары перевозятся тележками-роботами по складам и цехам.
А Вы там не приметили "человека и собаку"?
Теперь нп.
уже который раз попадаются в коде, внутри которого нужно лазить, такие пассажи:
bool allright = isallright();
if (allright == true){
...
почему тогда не так?
if ((allright == true) == true){
Я скажу только про дополнительную переменную - иногда её введение можно объяснить удобностью отладки. Можно ткнуть при откладке и посмотреть значение, чем запихивать в if сразу метод isallright. Но с некоторых пор (уже вроде давно) в Студии можно смотреть результат возврата метода в отладке просто наведя на него курсор. Поэтому сейчас лучше писать if(isallright()).
уже который раз попадаются в коде, внутри которого нужно лазить, такие пассажи:
Что именно тебе не нравится в этом коде?
Наличие отдельной перебенной? Это удобно при отладке. Да и при чтении кода это тоже удобнее. Ведь может быть так, что функция имеет гораздо более длинное имя да еще несколько параметров. С такой формой записи код получается в единов стиле.
Явное сравнение с true? - это просто явная запись. Как по мне, такая запись читается легче.
почему тогда не так?
Потому что это неудобно.