Механизм привязки данных (DataBinding), страница 10

Закрепить изменения в записи можно путем вызова метода EndEdit объекта класса DataRowView (именно он управляет текущей строкой таблицы). Покажем, как добыть текущую запись и вызвать метод EndEdit в реакции на событие BindingComplete объекта класса Binding. Этот объект неявно создается при вызове метода DataBindings.Add.

Для того, чтобы сравнить два разных подхода, все сказанное продемонстрируем не на примере TextBox'а, а на примере привязки свойства Checked элемента типа CheckBox. Мы привяжем его к текущей строке колонки Available таблицы Goods. В этой колонке хранятся данные типа bool, и они по типу соответствует свойству Checked нашего флажка (иначе, CheckBox'а).

chkAvailable.DataBindings.Add("Checked", dt, "Available", true,

DataSourceUpdateMode.OnPropertyChanged);

chkAvailable.DataBindings[0].BindingComplete +=

delegate(object binding, BindingCompleteEventArgs e)

{

if (e.BindingCompleteContext == BindingCompleteContext.DataSourceUpdate &&

e.BindingCompleteState == BindingCompleteState.Success)

{

DataRowView view = e.Binding.BindingManagerBase.Current as DataRowView;

if (null != view)

view.EndEdit(); // Force ADO.NET to commit the value

}

};

Здесь мы снова воспользовались услугами анонимного делегата. Для практики полезно реализовать те же действия с помощью обычного делегата. Проверьте работу ускоренного механизма привязки, управляя флажком chkAvailable. Затем создайте немигающий ErrorProvider и подключите к нашей таблице.

errorProvider.DataSource = dt;

Манипулируя данными поля tID (индекса строки таблицы), убедитесь, что валидатор errorProvider действует быстро, что обусловлено установкой режима OnPropertyChanged. Для сравнения этого режима с режимом, действующим по умолчанию (DataSourceUpdateMode.OnValidation), добавим привязку к полю tPrice.

Binding b = new Binding("Text", dt, "Price", true);

b.FormatString = "c";  // .NET Framework Currency format string

tPrice.DataBindings.Add(b);

В отличие от предыдущих вариантов привязки, здесь мы явно объявляем объект класса Binding, настраиваем его на денежный формат и лишь поле этого включаем режим слежения (типа OnValidation). Убедитесь, что слежение осуществляется в момент валидации содержимого поля редактирования, то есть, когда фокус ввода переходит в другое поле формы. Денежный формат работает так, что появляется рублевый суффикс, если у вас установлена русский вариант операционной системы Windows и не переустановлена соответствующая культура (CultureInfo).

Вместо валидатора (или совместно с валидатором) типа ErrorProvider вы можете использовать элемент, управляемый классом ToolTip. Он тоже способен сигнализировать об ошибке, но в виде текста. Покажем, как приспособить такой объект к полю tPrice. В конец метода BindToTable добавьте такой фрагмент кода.

ToolTip toolTip = new ToolTip ();

toolTip.IsBalloon = true;

toolTip.ToolTipTitle = "Binding Error:";

b.BindingComplete +=

delegate (object sender, BindingCompleteEventArgs e)

{

if (!string.IsNullOrEmpty (e.ErrorText))

toolTip.Show (e.ErrorText, tPrice, 2000);

};

и убедитесь, что подсказка toolTip неплохо справляется со своей задачей.

Новый рисунок

Обычно при наличии ошибок ввода ErrorProvider не позволяет перевести фокус в другой элемент управления, он захватывает фокус и даже не позволяет закрыть окно. Параметр FormClosingEventArgs e функции обработки события FormClosing несет информацию о валидации формы.

¨  Если данные формы прошли валидацию, то свойство Cancel этого параметра равно false. В обычном сценарии это позволяет закрыть форму (то есть, уничтожить ее, выполнив метод Dispose).

¨  Значение e.Cancel == true сигнализирует об ошибке и обычно отменяет (cancels) уничтожение формы.

¨  В нашем сценарии (вспомните начальные установки в классе MainForm) мы всегда игнорируем сигнал об ошибке и насильно скрываем (но не уничтожаем) окно текущей формы.