Использование правил проверки WPF и отключение кнопки «Сохранить» - PullRequest
27 голосов
/ 23 октября 2008

У меня есть страница, где несколько текстовых полей не могут быть пустыми до нажатия кнопки Сохранить.

<TextBox...

                <TextBox.Text>
                    <Binding Path ="LastName" UpdateSourceTrigger="PropertyChanged">

                        <Binding.ValidationRules>
                            <local:StringRequiredValidationRule />
                        </Binding.ValidationRules>                              
                    </Binding>
                </TextBox.Text>

Мое правило работает. У меня есть красная рамка вокруг моего текстового поля, пока я не введу значение. Поэтому теперь я хочу добавить это правило проверки к другим моим текстовым полям.

Теперь, как отключить кнопку Сохранить, пока на странице нет ошибок? Я не знаю, что проверить, чтобы увидеть, есть ли какие-либо ошибки проверки.

Ответы [ 8 ]

17 голосов
/ 23 января 2012
15 голосов
/ 30 апреля 2009

В коде для представления вы можете подключить Validation.ErrorEvent следующим образом;

this.AddHandler(Validation.ErrorEvent,new RoutedEventHandler(OnErrorEvent)); 

А потом

private int errorCount;
private void OnErrorEvent(object sender, RoutedEventArgs e)
{
    var validationEventArgs = e as ValidationErrorEventArgs;
    if (validationEventArgs  == null)
        throw new Exception("Unexpected event args");
    switch(validationEventArgs.Action)
    {
        case ValidationErrorEventAction.Added:
            {
                errorCount++; break;
            }
        case ValidationErrorEventAction.Removed:
            {
                errorCount--; break;
            }
        default:
            {
                throw new Exception("Unknown action");
            }
    }
    Save.IsEnabled = errorCount == 0;
}

Предполагается, что вы получите уведомление об удалении (что не произойдет, если вы удалите нарушающий элемент, пока он недействителен).

8 голосов
/ 24 октября 2008

Вы хотите использовать Validation.HasError присоединенное свойство.

В том же духе у Джоша Смита есть интересное прочтение Привязка к (Validation.Errors) [0] без создания отладочного выброса .

3 голосов
/ 22 сентября 2011
int count = 0;

private void LayoutRoot_BindingValidationError(object sender, ValidationErrorEventArgs e)
{
    if (e.Action == ValidationErrorEventAction.Added)
    {
        button1.IsEnabled = false;
        count++;
    }
    if (e.Action == ValidationErrorEventAction.Removed)
    {                
        count--;
        if (count == 0) button1.IsEnabled = true;
    }
}
2 голосов
/ 25 декабря 2012

это оно вам нужно проверить свойство элемента управления HasError из кода поведения:

и сделайте этот код нажатием кнопки сохранения

 BindingExpression bexp = this.TextBox1.GetBindingExpression(TextBox.TextProperty);
bexp.UpdateSource(); // this to refresh the binding and see if any error exist 
bool hasError = bexp.HasError;  // this is boolean property indique if there is error 

MessageBox.Show(hasError.ToString());
2 голосов
/ 16 ноября 2011

Вот вспомогательный метод, который отслеживает ошибки проверки объектов зависимостей (и всех его дочерних элементов) и вызывает делегат для уведомления об изменении. Он также отслеживает удаление детей с ошибками проверки.

 public static void AddErrorHandler(DependencyObject element, Action<bool> setHasValidationErrors)
        {
            var errors = new List<Tuple<object, ValidationError>>();

            RoutedEventHandler sourceUnloaded = null;

            sourceUnloaded = (sender, args) =>
                {
                    if (sender is FrameworkElement)
                        ((FrameworkElement) sender).Unloaded -= sourceUnloaded;
                    else
                        ((FrameworkContentElement) sender).Unloaded -= sourceUnloaded;

                    foreach (var error in errors.Where(err => err.Item1 == sender).ToArray())
                        errors.Remove(error);

                    setHasValidationErrors(errors.Any());
                };

            EventHandler<ValidationErrorEventArgs> errorHandler = (_, args) =>
                {
                    if (args.Action == ValidationErrorEventAction.Added)
                    {
                        errors.Add(new Tuple<object, ValidationError>(args.OriginalSource, args.Error));

                        if (args.OriginalSource is FrameworkElement)
                            ((FrameworkElement)args.OriginalSource).Unloaded += sourceUnloaded;
                        else if (args.OriginalSource is FrameworkContentElement)
                            ((FrameworkContentElement)args.OriginalSource).Unloaded += sourceUnloaded;
                    }
                    else
                    {
                        var error = errors
                            .FirstOrDefault(err => err.Item1 == args.OriginalSource && err.Item2 == args.Error);

                        if (error != null) 
                            errors.Remove(error);
                    }

                    setHasValidationErrors(errors.Any());
                };


            System.Windows.Controls.Validation.AddErrorHandler(element, errorHandler);
        } 
1 голос
/ 22 января 2016

Я пробовал несколько решений, указанных выше; однако, ни один из них не работал для меня.

Моя простая проблема

У меня есть простое окно ввода, которое запрашивает URI у пользователя, если значение TextBox не является допустимым Uri, тогда кнопку Okay следует отключить.

Мое простое решение

Вот что у меня сработало:

CommandBindings.Add(new CommandBinding(AppCommands.Okay,
            (sender, args) => DialogResult = true,
            (sender, args) => args.CanExecute = !(bool) _uriTextBoxControl.GetValue(Validation.HasErrorProperty)));
1 голос
/ 21 октября 2014

просто наследуйте вашу ViewModel из System.ComponentModel.IDataErrorInfo для проверки и из INotifyPropertyChanged, чтобы уведомить кнопку

сделать недвижимость:

    public bool IsValid
    {
        get
        {
            if (this.FloorPlanName.IsEmpty())
                return false;
            return true;
        }
    }

в xaml, подключите его к кнопке

<Button Margin="4,0,0,0" Style="{StaticResource McVMStdButton_Ok}" Click="btnDialogOk_Click" IsEnabled="{Binding IsValid}"/>

в переопределениях IDataErrorInfo, кнопка уведомления

public string this[string columnName]{
        get
        {
            switch (columnName)
            {
                case "FloorPlanName":
                    if (this.FloorPlanName.IsEmpty())
                    {
                        OnPropertyChanged("IsValid");
                        return "Floor plan name cant be empty";
                    }
                    break;
            }
        }
}
...