Одним из способов отсрочки проверки является установка свойства UpdateSourceTrigger=Explicit
в привязках. Если вы сделаете это, привязки не обновят исходные объекты и, следовательно, не вызовут ошибок проверки, пока вы явно не скажете привязкам сделать это. Когда нажата ваша кнопка, вы принудительно обновляете привязки, используя следующую строку для каждого элемента управления:
someTextBox.GetBindingExpression(TextBox.TextProperty).UpdateSource();
Затем ваши установщики свойств выдают исключения для недопустимых данных.
Этот подход может быть немного болезненным, если имеется довольно много элементов управления для принудительного обновления привязки.
Кроме того, принудительное обновление привязок должно выполняться в коде позади элемента управления. Если вы также используете команду с кнопкой, вы можете столкнуться с проблемой. Кнопки могут иметь как обработчик события Command, так и обработчик Click, и оба будут выполняться при нажатии кнопки, но я не знаю порядок, в котором это происходит, или даже если порядок можно гарантировать. Быстрый эксперимент показал, что обработчик событий был выполнен перед командой, но я не знаю, является ли это неопределенным поведением. Поэтому существует вероятность того, что команда будет запущена до того, как будут обновлены привязки.
Подход к программному созданию всплывающих подсказок для проверки состоит в том, чтобы связать другое свойство текстового поля и затем преднамеренно вызвать ошибку с этим связыванием.
'sapient' опубликовал полное решение, включая код , на форумах Silverlight (поиск сообщения от 07-08-2009 16:56). Короче говоря, он / она создает вспомогательный объект со свойством, метод получения которого генерирует исключение, привязывает свойство Tag
текстового поля к этому вспомогательному объекту и затем принудительно обновляет привязку.
код sapient был написан до выхода Silverlight 4. Мы «обновим» его / ее код до Silverlight 4. Класс ControlValidationHelper
станет следующим:
public class ControlValidationHelper : IDataErrorInfo
{
public string Message { get; set; }
public object ValidationError { get; set; }
public string Error
{
get { throw new NotImplementedException(); }
}
public string this[string columnName]
{
get { return Message; }
}
}
Достаточно легко запустить быстрое демо-приложение, чтобы попробовать это. Я создал следующие три элемента управления:
<TextBox x:Name="tbx" Text="{Binding Path=Text, ValidatesOnDataErrors=True, NotifyOnValidationError=True, Mode=TwoWay}" />
<Button Click="ForceError_Click">Force error</Button>
<Button Click="ClearError_Click">Clear error</Button>
Свойство Text
и обработчики событий для двух кнопок находятся в выделенном коде и имеют следующий вид:
public string Text { get; set; }
private void ForceError_Click(object sender, RoutedEventArgs e)
{
var helper = new ControlValidationHelper() { Message = "oh no!" };
tbx.SetBinding(Control.TagProperty, new Binding("ValidationError")
{
Mode = BindingMode.TwoWay,
NotifyOnValidationError = true,
ValidatesOnDataErrors = true,
UpdateSourceTrigger = UpdateSourceTrigger.Explicit,
Source = helper
});
tbx.GetBindingExpression(Control.TagProperty).UpdateSource();
}
private void ClearError_Click(object sender, RoutedEventArgs e)
{
BindingExpression b = tbx.GetBindingExpression(Control.TagProperty);
if (b != null)
{
((ControlValidationHelper)b.DataItem).Message = null;
b.UpdateSource();
}
}
Кнопка «Принудительная ошибка» должна привести к появлению ошибки проверки в текстовом поле, а кнопка «Очистить ошибку» должна заставить ее исчезнуть.
Один потенциальный недостаток этого подхода возникает, если вы используете ValidationSummary . ValidationSummary перечислит все ошибки проверки по ValidationError
, а не по имени каждого свойства.