Wie validiere ich zwei voneinander abhängige Eigenschaften?

8

Ich habe View - Modell mit 2 Eigenschaften: Aund Bund ich möchte , dass validieren A < B.

Unten ist meine vereinfachte Implementierung, bei der ich eine benutzerdefinierte Validierungsregel verwende. Da jede Eigenschaft unabhängig validiert wird, führt dies zu einem ärgerlichen Problem: Wenn der eingegebene AWert ungültig ist, bleibt dies auch nach einer Änderung so B, da die Validierung von Bnichts weiß A.

Dies ist auf dieser Demo zu sehen:

Aist nach der Eingabe ungültig 11, das ist da richtig 11 > 2. Ändern Bzu 22nicht wieder evalute A, habe ich zu bearbeiten AValidierung bestanden zu haben.

Was ich möchte? Ich möchte, dass nach dem Eintreten 22in Bden roten Rand (Validierungsfehler) verschwindet und Quellwerte A = 11, B = 22im Ansichtsmodell wären.

Wie kann ich bei der BValidierung die Validierung erzwingen, Anachdem der neue BWert mit der Quelle synchronisiert wurde?


Modell anzeigen:

public class ViewModel : INotifyPropertyChanged
{
    int _a;
    public int A
    {
        get => _a;
        set
        {
            _a = value;
            OnPropertyChanged();
        }
    }

    int _b;
    public int B
    {
        get => _b;
        set
        {
            _b = value;
            OnPropertyChanged();
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    public virtual void OnPropertyChanged([CallerMemberName] string property = "") =>
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(property));
}

Aussicht:

<StackPanel>
    <TextBox Margin="10" Text="{local:MyBinding A}" />
    <TextBox Margin="10" Text="{local:MyBinding B}" />
</StackPanel>

Code anzeigen:

public MainWindow()
{
    InitializeComponent();
    DataContext = new ViewModel { A = 1, B = 2 };
}

Bindung:

public class MyBinding : Binding
{
    public MyBinding(string path) : base(path)
    {
        UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
        ValidationRules.Add(new MyValidationRule());
    }
}

Validierungsregel:

public class MyValidationRule : ValidationRule
{
    public MyValidationRule() : base(ValidationStep.ConvertedProposedValue, false) { }

    public override ValidationResult Validate(object value, CultureInfo cultureInfo) => ValidationResult.ValidResult; // not used

    public override ValidationResult Validate(object value, CultureInfo cultureInfo, BindingExpressionBase owner)
    {
        var binding = owner as BindingExpression;
        var vm = binding?.DataItem as ViewModel;
        switch (binding.ResolvedSourcePropertyName)
        {
            case nameof(vm.A):
                if ((int)value >= vm.B)
                    return new ValidationResult(false, "A should be smaller than B");
                break;
            case nameof(vm.B):
                if ((int)value <= vm.A)
                    return new ValidationResult(false, "B should be bigger than A");
                break;
        }
        return base.Validate(value, cultureInfo, owner);
    }
}
Sinatr
quelle
2
Funktioniert es, wenn Sie auch OnPropertyChanged(nameof(B))den Setter von a aufrufen A(und das Äquivalent für den Setter von B)?
Dirk
1
Die Validierungsregel ist nur für einfache Anwendungsfälle wirklich geeignet. inotifydataerrorinfo in der VM ist der übliche Ansatz für alles Wesentliche. Sehen Sie sich die fließende Validierung an. Intro-Beispiel: gist.github.com/holymoo/11243164 fluentvalidation.net/built-in-validators Offhand - beide Eigenschaften hätten wahrscheinlich die gleiche Regel mit einer Prädikatprüfung, beide sind gut.
Andy
1
Nur relevant, wenn Sie ein Modell direkt verfügbar machen. Belichten Sie ein Modell nicht direkt. Verwenden Sie Ansichtsmodelle. Nur gültige Daten festschreiben.
Andy
1
@ Sinatr: "Ich finde das Konzept der Validierungsregel korrekter" ist falsch. Sie sollten INotifyDataErrorInfoin Ihrem Ansichtsmodell implementieren, wenn Sie diese Art der Validierung durchführen möchten. Es wird nicht von Validierungsregeln unterstützt.
mm8
1
@Rekshino, ja, ich habe auch darüber nachgedacht, wann ich validieren soll A: vor oder nach der Validierung B(mit anderen Worten, bevor der Wert von B akzeptiert und mit der Quelle oder danach synchronisiert wird). Bestellangelegenheit. Und tatsächlich muss ich zuerst alle geänderten Werte zur Hand haben und erst dann die Validierung in normaler Reihenfolge durchführen.
Sinatr

Antworten:

6

ValidationRules Die Ungültigmachung einer Eigenschaft beim Festlegen einer anderen Eigenschaft wird nicht unterstützt.

Sie sollten dies INotifyDataErrorInfoin Ihrem Ansichtsmodell implementieren und das ErrorsChangedEreignis auslösen, wenn Sie den Validierungsstatus für eine Eigenschaft aktualisieren möchten.

In diesem TechNet-Artikel finden Sie ein Beispiel .

mm8
quelle