Принудительная проверка связанных элементов управления в WPF
У меня есть диалог WPF с несколькими текстовыми полями на нем.
Текстовые поля привязаны к моему бизнес-объекту и имеют правила проверки WPF.
проблема в том, что пользователь может отлично нажать кнопку " ОК " и закрыть диалоговое окно, фактически не вводя данные в текстовые поля. Правила проверки никогда не срабатывают, так как пользователь даже не пытался ввести информацию в текстовые поля.
можно ли принудительно проверить проверку и определить, являются ли некоторые правила проверки сломался?
Я был бы в состоянии сделать это, когда пользователь пытается закрыть диалоговое окно и запретить ему делать это, если какие-либо правила проверки нарушены.
спасибо.
6 ответов:
у нас эта проблема в нашем приложении, а также. Проверка срабатывает только при обновлении Привязок, поэтому вам нужно обновить их вручную. Мы делаем это в окне загружается событие:
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(); }это заставит шаблон ошибки (красный контур) появиться и установить проверка.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>
в 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>
вот альтернативный способ, который не требует вызова " 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); }
используйте метод, предложенный выше Робертом Макни. Например:
//force initial validation foreach (FrameworkElement item in grid1.Children) { if (item is TextBox) { TextBox txt = item as TextBox; txt.GetBindingExpression(TextBox.TextProperty).UpdateSource(); } }но, убедитесь, что связанные элементы управления являются видимыми перед запуском этого кода!
на всякий случай, если кто-то случайно найдет этот старый вопрос и ищет ответ, который обращается к комментарию Monstieur о руководстве по пользовательскому интерфейсу, я сделал следующее:
Xaml
<TextBox.Text> <Binding Path="TextValue" Mode="TwoWay" UpdateSourceTrigger="PropertyChanged"> <Binding.ValidationRules> <local:RequiredFieldValidationRule> <local:RequiredFieldValidationRule.IsRequiredField> <local:BoolValue Value="{Binding Data.Required, Source={StaticResource proxy}}" /> </local:RequiredFieldValidationRule.IsRequiredField> <local:RequiredFieldValidationRule.ValidationFailed> <local:BoolValue Value="{Binding Data.HasValidationError, Mode=TwoWay, Source={StaticResource proxy}}" /> </local:RequiredFieldValidationRule.ValidationFailed> </local:RequiredFieldValidationRule> </Binding.ValidationRules> </Binding> </TextBox.Text>RequiredFieldValidationRule:
public class RequiredFieldValidationRule : ValidationRule { private BoolValue _isRequiredField; public BoolValue IsRequiredField { get { return _isRequiredField; } set { _isRequiredField = value; } } private BoolValue _validationFailed; public BoolValue ValidationFailed { get { return _validationFailed; } set { _validationFailed = value; } } public override ValidationResult Validate(object value, CultureInfo cultureInfo) { ValidationFailed.Value = IsRequiredField.Value && (value == null || value.ToString().Length == 0); return new ValidationResult(!ValidationFailed.Value, ValidationFailed.Value ? "This field is mandatory" : null); } }в классе, который Xaml связывает с
private bool _hasValidationError; public bool HasValidationError { get { return _hasValidationError; } set { _hasValidationError = value; NotifyPropertyChanged(nameof(HasValidationError)); } } public void InitialisationMethod() // Or could be done in a constructor { _hasValidationError = Required; // Required is a property indicating whether the field is mandatory or not }затем я скрываю свою кнопку сохранения с помощью связанного свойства, если какой-либо из моих объектов имеет HasValidationError = true.
надеюсь, что это поможет кто-то.
используя 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 метод
Comments