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

Здесь есть несколько обычных текстовых полей, поле ввода числа и поле для e-mail’a. Зададим следующие правила для нашей формы:
Поля Фамилия, Имя и Отчество должны быть заполнены как минимум одним печатным (не whitespace) символом:
txtSurname .ValidateControl() .IsNotNullOrWhitespace(); txtName .ValidateControl() .IsNotNullOrWhitespace(); txtMiddleName .ValidateControl() .IsNotNullOrWhitespace();
Возраст должен быть не менее 16 лет. Если указанный возраст менее 21 года – необходимо вывести предупреждение, но разрешить сохранить форму:
nmAge .ValidateControl() .IsTrue(ctl => ctl.Value >= 16, "Возраст должен быть не менее 16 лет.", ValidationType.Required) .IsTrue(ctl => ctl.Value >= 21, "Некоторый контент (21+) для вас будет недоступен.", ValidationType.Optional);
Поле e-mail должно быть заполнено корректным значением (или по крайней мере похожим на e-mail):
txtEMail .ValidateControl() .IsValidEMail(false);
Если все поля заполнены правильно – разрешить нажатие кнопки «Сохранить», иначе – нет:
butSave .ValidateControl() .EnableByValidationResult();
public partial class frmMain : Form { public frmMain() { InitializeComponent(); // проверим, что текстовые поля заполнены txtSurname .ValidateControl() .IsNotNullOrWhitespace(); txtName .ValidateControl() .IsNotNullOrWhitespace(); txtMiddleName .ValidateControl() .IsNotNullOrWhitespace(); // зададим жесткое ограничение в 16 лет // и не жесткое ограничение (предупреждение не препятствующее вводу формы) в 21 год nmAge .ValidateControl() .IsTrue(ctl => ctl.Value >= 16, "Возраст должен быть не менее 16 лет.", ValidationType.Required) .IsTrue(ctl => ctl.Value >= 21, "Некоторый контент (21+) для вас будет недоступен.", ValidationType.Optional); // включим проверку на ввод корректного e-mail'а в этом поле txtEMail .ValidateControl() .IsValidEMail(false); // по результатам валидации будем разрешать/запрещать указанную кнопку butSave .ValidateControl() .EnableByValidationResult(); } }
Что мы получим при запуске формы? Во первых: мы получим удобное подсвечивание каждого поля, значение которого заполнено некорректными данными. Во вторых: если подвести курсор мыши к индикатору мы увидим что именно хочет от нас форма:

В третьих: кнопка «Сохранить» будет доступна к нажатию только после успешной валидации данных.
Хорошо, с простой формой мы разобрались, а как быть с формой посложнее? Усложним задачу. Будем делать импровизированную форму поиска статей для Хабра:

Мы имеем три фильтра, при выборе которых должны активироваться проверки заданных условий для каждого фильтра. Плюс активация контролов, которые относятся к выбранному фильтру. Хотелось бы отметить, что управление состоянием контролов не совсем относится к валидации данных, но в данном случае мы не будем заострять на этом внимание.
Активацию контролов будем делать так:
// список чекбоксов с категориями var categoryCheckBoxes = pnlCategories.Controls.Cast<CheckBox>(); // управление состоянием контролов в зависимости от включенных чекбоксов dtBegin.EnableByTimer(() => chkFilterByDate.Checked); dtEnd.EnableByTimer(() => chkFilterByDate.Checked); pnlCategories.EnableByTimer(() => chkFilterByCategory.Checked); pnlTextFilter.EnableByTimer(() => chkFilterByText.Checked);
Теперь правила валидации. Если фильтр по дате включен, то начальная дата должна быть меньше либо равна конечной. Начальная дата не может быть раньше 1990 года. Валидация будет происходить в обоих DatePicker’ах, но индикация будет отображаться только на dtEnd:
dtEnd .ValidateControl() .IsTrue(ctl => !chkFilterByDate.Checked || dtBegin.Value >= new DateTime(1990, 1, 1), "Начальная дата отбора не может быть раньше 1990 года") .IsTrue(ctl => !chkFilterByDate.Checked || dtBegin.Value <= dtEnd.Value, "Начальная дата должна быть меньше или равной конечной");
Если осуществляется фильтрация по категориям, то необходимо выбрать как минимум одну категорию:
pnlCategories .ValidateControl() .IsTrue(ctl => !chkFilterByCategory.Checked || categoryCheckBoxes.Any(c => c.Checked), "Необходимо выбрать категорию");
Если осуществляется поиск текста, то необходимо задать текст и выбрать где его искать:
pnlTextFilter .ValidateControl() .IsTrue(ctl => !chkFilterByText.Checked || chkSearchTextInBody.Checked || chkSearchTextInHeader.Checked, "Необходимо выбрать места поиска текста") .IsTrue(ctl => !chkFilterByText.Checked || !string.IsNullOrWhiteSpace(txtSearchText.Text), "Необходимо задать текст");
Также, для успешной валидации формы, должен быть задан хотя бы один из фильтров для поиска:
gbSearchParameters .ValidateControl() .IsTrue(ctl => chkFilterByCategory.Checked || chkFilterByDate.Checked || chkFilterByText.Checked, "Необходимо задать условия поиска.");
Ну и по результатам валидации формы активируем главную действующую кнопку:
butSearch .ValidateControl() .EnableByValidationResult();
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using Teleavtomatika.Forms; namespace Teleavtomatika_Form_Validation { public partial class frmMain2 : Form { public frmMain2() { InitializeComponent(); // список чекбоксов с категориями var categoryCheckBoxes = pnlCategories.Controls.Cast<CheckBox>(); // управление состоянием контролов в зависимости от включенных чекбоксов dtBegin.EnableByTimer(() => chkFilterByDate.Checked); dtEnd.EnableByTimer(() => chkFilterByDate.Checked); pnlCategories.EnableByTimer(() => chkFilterByCategory.Checked); pnlTextFilter.EnableByTimer(() => chkFilterByText.Checked); // теперь правила валидации: // если фильтр по дате включен, то начальная дата должна быть меньше либо равна конечной // начальная дата не может быть раньше 1990 года // валидация будет происходить в обоих DatePicker'ах, но индикация будет отображаться только на dtEnd dtEnd .ValidateControl() .IsTrue(ctl => !chkFilterByDate.Checked || dtBegin.Value >= new DateTime(1990, 1, 1), "Начальная дата отбора не может быть раньше 1990 года") .IsTrue(ctl => !chkFilterByDate.Checked || dtBegin.Value <= dtEnd.Value, "Начальная дата должна быть меньше или равной конечной"); // если осуществляется фильтрация по категориям // то необходимо выбрать как минимум одну категорию pnlCategories .ValidateControl() .IsTrue(ctl => !chkFilterByCategory.Checked || categoryCheckBoxes.Any(c => c.Checked), "Необходимо выбрать категорию"); // если осуществляется поиск текста // то необходимо задать текст // и выбрать где его искать pnlTextFilter .ValidateControl() .IsTrue(ctl => !chkFilterByText.Checked || chkSearchTextInBody.Checked || chkSearchTextInHeader.Checked, "Необходимо выбрать места поиска текста") .IsTrue(ctl => !chkFilterByText.Checked || !string.IsNullOrWhiteSpace(txtSearchText.Text), "Необходимо задать текст"); // должен быть задан хотя-бы один из фильтров для поиска gbSearchParameters .ValidateControl() .IsTrue(ctl => chkFilterByCategory.Checked || chkFilterByDate.Checked || chkFilterByText.Checked, "Необходимо задать условия поиска."); // Ну и по результатам валидации формы активируем главную действующую кнопку "Найти": butSearch .ValidateControl() .EnableByValidationResult(); } } }
Посмотреть как это работает в живую можно на видео:
Исходники тут.
ссылка на оригинал статьи http://habrahabr.ru/post/209820/
Добавить комментарий