Проверка синтаксиса связанных элементов управления в WPF
У меня есть диалог WPF с несколькими текстовыми полями на нем.
Текстовые поля привязаны к моему бизнес-объекту и имеют правила проверки WPF.
Проблема в том, что пользователь может отлично нажать кнопку "ОК" и закрыть диалоговое окно, фактически не введя данные в текстовые поля. Правила проверки никогда не срабатывают, поскольку пользователь даже не пытался ввести информацию в текстовые поля.
Можно ли принудительно выполнить проверки проверки и определить, нарушены ли некоторые правила проверки?
Я мог бы сделать это, когда пользователь попытается закрыть диалог и запретить ему делать это, если будут нарушены какие-либо правила проверки.
Спасибо.
Ответы
Ответ 1
У нас есть эта проблема и в нашем приложении. Проверка выполняется только при обновлении привязок, поэтому вам необходимо обновить их вручную. Мы делаем это в окне Loaded событие:
public void Window_Loaded(object sender, RoutedEventArgs e)
{
// we manually fire the bindings so we get the validation initially
txtName.GetBindingExpression(TextBox.TextProperty).UpdateSource();
txtCode.GetBindingExpression(TextBox.TextProperty).UpdateSource();
}
Появится шаблон ошибки (красный контур) и установите свойство Validation.HasError, которое мы вызываем кнопку OK для отключить:
<Button x:Name="btnOK" Content="OK" IsDefault="True" Click="btnOK_Click">
<Button.Style>
<Style TargetType="{x:Type Button}">
<Setter Property="IsEnabled" Value="false" />
<Style.Triggers>
<!-- Require the controls to be valid in order to press OK -->
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding ElementName=txtName, Path=(Validation.HasError)}" Value="false" />
<Condition Binding="{Binding ElementName=txtCode, Path=(Validation.HasError)}" Value="false" />
</MultiDataTrigger.Conditions>
<Setter Property="IsEnabled" Value="true" />
</MultiDataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
Ответ 2
В 3.5SP1/3.0SP2 они также добавили новое свойство в базу ValidationRule, а именно ValidatesOnTargetUpdated = "True" . Это вызовет проверку, как только объект-источник привязан, а не только при обновлении целевого элемента управления. Это может быть не совсем то, что вы хотите, но неплохо увидеть сначала все, что вам нужно исправить.
Работает примерно так:
<TextBox.Text>
<Binding Path="Amount" StringFormat="C">
<Binding.ValidationRules>
<validation:RequiredValidationRule
ErrorMessage="The pledge amount is required."
ValidatesOnTargetUpdated="True" />
<validation:IsNumericValidationRule
ErrorMessage="The pledge amount must be numeric."
ValidationStep="ConvertedProposedValue"
ValidatesOnTargetUpdated="True" />
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
Ответ 3
Вот альтернативный способ, который не требует вызова "UpdateSource()" или "UpdateTarget()":
var binding = thingToValidate.GetBinding(propertyToValidate);
foreach (var rule in binding.ValidationRules)
{
var value = thingToValidate.GetValue(propertyToValidate);
var result = rule.Validate(value, CultureInfo.CurrentCulture);
if (result.IsValid)
continue;
var expr = BindingOperations.GetBindingExpression(thingToValidate, propertyToValidate);
if (expr == null)
continue;
var validationError = new ValidationError(rule, expr);
validationError.ErrorContent = result.ErrorContent;
Validation.MarkInvalid(expr, validationError);
}
Ответ 4
Используйте метод, предложенный Робертом Макни. Например:
//force initial validation
foreach (FrameworkElement item in grid1.Children)
{
if (item is TextBox)
{
TextBox txt = item as TextBox;
txt.GetBindingExpression(TextBox.TextProperty).UpdateSource();
}
}
Но, УБЕДИТЕСЬ, что связанные элементы управления являются Visibles до запуска этого кода!
Ответ 5
используя INotifyPropertychanged в вашем объекте данных
public class MyObject : INotifyPropertyChanged
{
string _MyPropertyToBind = string.Empty;
public string MyPropertyToBind
{
get
{
return _MyPropertyToBind;
}
set
{
_MyPropertyToBind = value;
NotifyPropertyChanged("MyPropertyToBind");
}
}
public void NotifyPropertyChanged(string property)
{
if (this.PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(property));
}
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
#endregion
}
вы можете добавить в свой код следующий код
<TextBox Text="{Binding MyPropertyToBind, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" >
Текстовое поле воспринимает событие propertychanged объекта datacontext (MyObjet в нашем примере) и предполагает, что оно запущено, когда исходные данные были обновлены.
он автоматически принудительно обновляет элемент управления
Не нужно называть себя методом UpdateTarget