web-dev-qa-db-fra.com

Utilisation des règles de validation WPF et désactivation d'un bouton «Enregistrer»

J'ai une page où quelques zones de texte ne peuvent pas être vides avant de cliquer sur un bouton Enregistrer.

<TextBox...

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

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

Ma règle fonctionne. J'ai une bordure rouge autour de ma zone de texte jusqu'à ce que j'entre une valeur. Alors maintenant, je veux ajouter cette règle de validation à mes autres zones de texte.

Maintenant, comment désactiver le bouton Enregistrer jusqu'à ce que la page ne contienne aucune erreur? Je ne sais pas quoi vérifier pour voir s'il y a des erreurs de validation.

27
ScottG
18
Developer

Sur le codebehind pour la vue, vous pouvez câbler le Validation.ErrorEvent comme ceci;

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

Puis

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;
}

Cela suppose que vous serez averti de la suppression (ce qui ne se produira pas si vous supprimez l'élément incriminé alors qu'il n'est pas valide).

15
Christoph

Vous souhaitez utiliser Validation.HasError propriété jointe.

Dans le même ordre d'idées, Josh Smith a une lecture intéressante sur Binding to (Validation.Errors) [0] sans création de débogage .

8
Todd White
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;
    }
}
3
Nihal

Voici une méthode d'assistance qui suit les erreurs de validation sur les objets de dépendance (et tous ses enfants) et appelle délégué pour informer de la modification. Il suit également la suppression des enfants avec des erreurs de validation.

 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);
        } 
2
andrey.tsykunov

c'est ce dont vous avez besoin pour vérifier la propriété de contrôle HasError à partir du code derrière

et faites ce code dans le bouton Enregistrer cliquez

 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
Bilal

J'ai essayé plusieurs des solutions indiquées ci-dessus; cependant, aucun d'entre eux n'a travaillé pour moi.

Mon problème simple

J'ai une fenêtre d'entrée simple qui demande un URI à l'utilisateur, si la valeur TextBox n'est pas un Uri valide, alors le bouton Okay doit être désactivé.

Ma solution simple

Voici ce qui a fonctionné pour moi:

CommandBindings.Add(new CommandBinding(AppCommands.Okay,
            (sender, args) => DialogResult = true,
            (sender, args) => args.CanExecute = !(bool) _uriTextBoxControl.GetValue(Validation.HasErrorProperty)));
1
Kabuo

héritez juste de votre ViewModel de System.ComponentModel.IDataErrorInfo pour Validate et de INotifyPropertyChanged pour notifier le bouton

faire une propriété:

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

en xaml, connectez-le au bouton

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

dans les remplacements IDataErrorInfo, notifiez btutton

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

Parce qu'il est toujours manquant, voici une adaptation de la réponse du développeur au cas où le lien disparaîtrait:

XAML:

<TextBox.Text Validation.Error="handleValidationError">
    <Binding Path ="LastName" 
             UpdateSourceTrigger="PropertyChanged"
             NotifyOnValidationError="True">
        <Binding.ValidationRules>
            <local:StringRequiredValidationRule />
        </Binding.ValidationRules>                              
    </Binding>
</TextBox.Text>
<Button IsEnabled="{Binding HasNoValidationErrors}"/>

CodeBehind/C #:

private int _numberOfValidationErrors;
public bool HasNoValidationErrors => _numberOfValidationErrors = 0;

private void handleValidationError(object sender, ValidationErrorEventArgs e)
{
    if (e.Action == ValidationErrorEventAction.Added)
        _numberOfValidationErrors++;
    else
        _numberOfValidationErrors--;
}
0
Gregor A. Lamche