Доступ к правилам проверки управления WPF из кода - PullRequest
16 голосов
/ 25 ноября 2010

XAML:

  <TextBox Name="textboxMin">
      <TextBox.Text>
          <Binding Path="Max">
              <Binding.ValidationRules>
                  <local:IntValidator/>
              </Binding.ValidationRules>
          </Binding>
      </TextBox.Text>
  </TextBox>

Код:

void buttonOK_Click(object sender, RoutedEventArgs e)
{
    // I need to know here whether textboxMin validation is OK
    // textboxMin. ???

    // I need to write something like:
    // if ( textboxMin.Validation.HasErrors )
    //     return;
}

Было бы также неплохо узнать, как отключить кнопку OK, если хотя бы один из диалоговых элементов управления не прошел проверку - в XAML с использованием привязки. Таким образом, мне не нужно проверять состояние проверки в коде.

Ответы [ 3 ]

24 голосов
/ 25 ноября 2010

Validation.HasError является вложенным свойством, поэтому вы можете проверить его на textboxMin следующим образом

void buttonOK_Click(object sender, RoutedEventArgs e)
{
    if (Validation.GetHasError(textboxMin) == true)
         return;
}

Чтобы запустить все ValidationRules для TextProperty в коде позади, вы можете получить BindingExpression и вызвать UpdateSource

BindingExpression be = textboxMin.GetBindingExpression(TextBox.TextProperty);
be.UpdateSource();

Обновление

Чтобы выполнить привязку, чтобы отключить кнопку в случае какой-либо проверки, потребуется выполнить несколько шагов.

Сначала убедитесь, что все привязки добавляют NotifyOnValidationError= "True".Пример

<TextBox Name="textboxMin">
    <TextBox.Text>
        <Binding Path="Max" NotifyOnValidationError="True">
            <Binding.ValidationRules>
                <local:IntValidator/>
            </Binding.ValidationRules>
        </Binding>
    </TextBox.Text>
</TextBox>

Затем мы подключаем EventHandler к событию Validation.Error в окне.

<Window ...
        Validation.Error="Window_Error">

И в коде позади мы добавляем и удаляем ошибки проверки в наблюдаемой коллекции какони приходят и уходят

public ObservableCollection<ValidationError> ValidationErrors { get; private set; } 
private void Window_Error(object sender, ValidationErrorEventArgs e)
{
    if (e.Action == ValidationErrorEventAction.Added)
    {
        ValidationErrors.Add(e.Error);
    }
    else
    {
        ValidationErrors.Remove(e.Error);
    }
}

И тогда мы можем связать IsEnabled кнопки с ошибками Validation.Count следующим образом

<Button ...>
    <Button.Style>
        <Style TargetType="Button">
            <Setter Property="IsEnabled" Value="False"/>
            <Style.Triggers>
                <DataTrigger Binding="{Binding ValidationErrors.Count}" Value="0">
                    <Setter Property="IsEnabled" Value="True"/>
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </Button.Style>
</Button>
6 голосов
/ 25 ноября 2010

вам нужно сначала получить Binding, прежде чем вы получите правила

    Binding b=  BindingOperations.GetBinding(textboxMin,TextBox.TextProperty);
    b.ValidationRules

, иначе вы можете получить BindingExpression и проверить свойство HasError

 BindingExpression be1 = BindingOperations.GetBindingExpression (textboxMin,TextBox.TextProperty);

be1.HasError
0 голосов
/ 12 мая 2018

Большое спасибо Фредрику Хедбладу за его решение. Это помогло мне также. Я также согласен с Лукашом Котеном, что его лучше всего использовать как поведение. Таким образом, в слое представления нет смешанной логики приложения, и модели представления не нужно беспокоиться о дублировании валидации, чтобы просто иметь ее там. Вот моя версия через поведение:

Как сказал Фредрик Хедблад, сначала убедитесь, что у любого проверяющего элемента управления есть обязательный атрибут NotifyOnValidationError = "True".

Вот логика представления ... намного проще ...

xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"

и затем прямо под тегом начала окна

    Height="Auto" Width="Auto">
<i:Interaction.Behaviors>
    <behavior:ValidationErrorMappingBehavior HasValidationError="{Binding IsInvalid, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
</i:Interaction.Behaviors

Тогда для кнопки просто свяжите команду, как обычно. Мы будем использовать базовые принципы привязки модели представления, чтобы отключить ее с помощью RelayCommand.

<Button x:Name="OKButton" Content="OK" Padding="5,0" MinWidth="70" Height="23"
                HorizontalAlignment="Right" VerticalAlignment="Bottom" Margin="5,5,0,0"
                Command="{Binding OKCommand}"/>

А теперь модель представления с ее основным свойством и командой

    private bool _isInvalid = false;
    public bool IsInvalid
    {
        get { return _isInvalid; }
        set { SetProperty<bool>(value, ref _isInvalid); }
    }

    private ICommand _okCommand;
    public ICommand OKCommand
    {
        get
        {
            if (_okCommand == null)
            {
                _okCommand = new RelayCommand(param => OnOK(), canparam => CanOK());
            }

            return _okCommand;
        }
    }

    private void OnOK()
    {
        //  this.IsInvalid = false, so we're good... let's just close
        OnCloseRequested();
    }

    private bool CanOK()
    {
        return !this.IsInvalid;
    }

А теперь, поведение

using System.Windows;
using System.Windows.Controls;
using System.Windows.Interactivity;

namespace UI.Behavior
{
public class ValidationErrorMappingBehavior : Behavior<Window>
{
    #region Properties

    public static readonly DependencyProperty ValidationErrorsProperty = DependencyProperty.Register("ValidationErrors", typeof(ObservableCollection<ValidationError>), typeof(ValidationErrorMappingBehavior), new PropertyMetadata(new ObservableCollection<ValidationError>()));

    public ObservableCollection<ValidationError> ValidationErrors
    {
        get { return (ObservableCollection<ValidationError>)this.GetValue(ValidationErrorsProperty); }
        set { this.SetValue(ValidationErrorsProperty, value); }
    }

    public static readonly DependencyProperty HasValidationErrorProperty = DependencyProperty.Register("HasValidationError", typeof(bool), typeof(ValidationErrorMappingBehavior), new PropertyMetadata(false));

    public bool HasValidationError
    {
        get { return (bool)this.GetValue(HasValidationErrorProperty); }
        set { this.SetValue(HasValidationErrorProperty, value); }
    }

    #endregion

    #region Constructors

    public ValidationErrorMappingBehavior()
        : base()
    { }

    #endregion

    #region Events & Event Methods

    private void Validation_Error(object sender, ValidationErrorEventArgs e)
    {
        if (e.Action == ValidationErrorEventAction.Added)
        {
            this.ValidationErrors.Add(e.Error);
        }
        else
        {
            this.ValidationErrors.Remove(e.Error);
        }

        this.HasValidationError = this.ValidationErrors.Count > 0;
    }

    #endregion

    #region Support Methods

    protected override void OnAttached()
    {
        base.OnAttached();
        Validation.AddErrorHandler(this.AssociatedObject, Validation_Error);
    }

    protected override void OnDetaching()
    {
        base.OnDetaching();
        Validation.RemoveErrorHandler(this.AssociatedObject, Validation_Error);
    }

    #endregion
  }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...