Làm thế nào để xác nhận hai thuộc tính phụ thuộc vào nhau?


8

Tôi có quan điểm mô hình với 2 thuộc tính: ABvà tôi muốn xác nhận rằng A < B.

Dưới đây là triển khai đơn giản hóa của tôi, nơi tôi sử dụng quy tắc xác thực tùy chỉnh. Vì mỗi thuộc tính được xác nhận độc lập, dẫn đến một vấn đề gây khó chịu: nếu Agiá trị được nhập không hợp lệ, thì nó vẫn tồn tại ngay cả sau khi thay đổi B, vì xác Bthực không biết gì về nó A.

Điều này có thể được nhìn thấy trên bản demo này:

Akhông hợp lệ sau khi nhập 11, mà của sửa từ 11 > 2. Thay đổi Bthành 22không đánh giá lại A, tôi phải chỉnh sửa Ađể thông qua xác nhận.

Những gì tôi muốn? Tôi muốn rằng sau khi tham gia 22vào Bviền đỏ (lỗi xác thực) sẽ biến mất và A = 11, B = 22sẽ là các giá trị nguồn trong mô hình xem.

Làm thế nào tôi có thể Bxác nhận bằng cách nào đó buộc Axác thực sau khi Bgiá trị mới được đồng bộ hóa với nguồn?


Xem mô hình:

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

Lượt xem:

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

Xem mã:

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

Ràng buộc:

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

Quy tắc xác nhận:

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

2
Nó có hoạt động không nếu bạn cũng gọi OnPropertyChanged(nameof(B))trong setter của một A(và tương đương với setter của B)?
Dirk

1
Xác nhận chỉ thực sự phù hợp với các trường hợp sử dụng đơn giản. inotifydataerrorinfo trong vm là cách tiếp cận thông thường cho bất cứ điều gì đáng kể. Hãy nhìn vào xác nhận thông thạo. Ví dụ giới thiệu: gist.github.com/holymoo/11243164 fluentvalidation.net/built-in-validators Offhand - cả hai thuộc tính có thể có cùng quy tắc với kiểm tra vị ngữ cả hai đều tốt.
Andy

1
Chỉ liên quan nếu bạn trực tiếp phơi bày một mô hình. Đừng trực tiếp phơi bày một mô hình. Sử dụng chế độ xem. Chỉ cam kết dữ liệu hợp lệ.
Andy

1
@Sinatr: "Tôi thấy khái niệm quy tắc xác thực đúng hơn" là sai. Bạn nên thực hiện INotifyDataErrorInfotrong mô hình xem của mình nếu bạn muốn thực hiện loại xác nhận này. Nó không được hỗ trợ bởi các quy tắc xác nhận.
mm8

1
@Rekshino, aye, tôi cũng đã suy nghĩ khi nào nên xác nhận A: trước hoặc sau khi xác thực B(nói cách khác trước khi giá trị của B được chấp nhận và đồng bộ hóa với nguồn hoặc sau). Vấn đề đặt hàng. Và thực sự trước tiên tôi phải có tất cả các giá trị được sửa đổi và chỉ sau đó thực hiện xác nhận theo thứ tự bình thường.
Sinatr

Câu trả lời:


6

ValidationRules không hỗ trợ vô hiệu hóa một tài sản khi thiết lập một tài sản khác.

Những gì bạn nên làm là triển khai INotifyDataErrorInfotrong mô hình xem của bạn và nâng cao ErrorsChangedsự kiện bất cứ khi nào bạn muốn làm mới trạng thái xác thực cho một thuộc tính.

Có một ví dụ có sẵn trong bài viết này của TechNet .

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.