2012-04-03 18 views
15

Tôi có một Cửa sổ dựa trên MVVM có nhiều điều khiển và Mô hình của tôi triển khai IDataErrorInfo.Làm cách nào để buộc cập nhật lỗi xác thực trên Chế độ xem từ ViewModel bằng IDataErrorInfo?

Ngoài ra còn có nút SaveCommand, thực hiện xác thực bằng cách phân tích thuộc tính Model.Error.

Chế độ xem hiển thị đường viền màu đỏ mặc định xung quanh các điều khiển có lỗi chỉ khi tôi thay đổi giá trị của điều khiển cụ thể hoặc khi tôi thông báo về thay đổi thuộc tính đó bằng PropertyChanged.

Làm cách nào để bắt buộc Chế độ xem hiển thị tất cả các lỗi Xác thực ngay cả khi tôi không chạm vào các điều khiển?

Tất cả các ràng buộc xác thực của tôi bao gồm ValidatesOnDataErrors=True, NotifyOnValidationError=True.

Tôi biết một giải pháp là có một hộp tổng hợp với tất cả các lỗi, nhưng tôi muốn hiển thị lỗi trên cơ sở trên mỗi điều khiển.

Tôi không muốn kích hoạt Model.NotifyPropertyChanged cho mỗi thuộc tính bị ràng buộc từ ViewModel.

Tôi sử dụng WPF 4.0, không phải Silverlight, vì vậy INotifyDataErrorInfo sẽ không hoạt động.

Trả lời

12

Bạn đề cập đến rằng bạn không muốn tăng thuộc tính đã thay đổi cho các thuộc tính mà bạn liên kết, nhưng đó thực sự là cách đơn giản nhất để thực hiện việc này. Gọi PropertyChanged không có tham số sẽ tăng cho tất cả các thuộc tính trong viewmodel của bạn.

Hoặc bạn có thể cập nhật các ràng buộc (và lực lượng kiểm tra hợp lệ) trên bất kỳ kiểm soát như thế này:

myControl.GetBindingExpression(ControlType.ControlProperty).UpdateSource(); 
+2

Cảm ơn bạn đã lừa với PropertyChanged. Tôi không biết điều đó là có thể. Tôi đã tìm thấy một cuộc thảo luận khác về chủ đề này: http://stackoverflow.com/questions/1135012/wpf-mvvm-can-a-single-propertychanged-update-all-the-data-bindings-of-a-datate nếu ai cũng quan tâm. Đây là câu trả lời hay nếu ai đó có một viewModel đơn giản, đơn giản.Tuy nhiên tôi có một cái nhìn phức tạp với ViewModels lồng nhau vì vậy tôi sẽ phải viết mã để gọi PropertyChanged một lần cho mỗi lồng nhau ràng buộc Model/ViewModel mà thực hiện INotifyPropertyChanged – surfen

+0

Thật tốt khi biết mẹo này nếu muốn cập nhật chỉ một phần của khung nhìn liên quan cho một ViewModel cụ thể – surfen

+0

myControl.GetBindingExpression (ControlType.ControlProperty) .UpdateTarget(); thực sự nhận được xác thực của bạn được cập nhật mà không cập nhật thuộc tính nguồn của bạn. – r41n

2

Giải pháp tốt nhất mà tôi đã tìm thấy cho đến nay hoạt động là thay đổi DataContext thành null và quay lại ví dụ của ViewModel.

này gây nên các bản cập nhật cho các điều khiển trên quan điểm cho rằng có DataContext ràng buộc để InnerViewModel:

public void ForceUpdateErrors() { 
    var tmpInnerVM = _mainViewModel.InnerViewModel; 
    _mainViewModel.InnerViewModel = null; 
    _mainViewModel.InnerViewModel = tmpInnerVM; 
} 

Bạn nên kiểm tra nếu không có dữ liệu bị mất sau khi lừa này. Tôi đã có một trường hợp mã này kích hoạt cập nhật nguồn cho ComboBox.SelectedItem với null nhưng tôi quản lý để giải quyết nó. Nguyên nhân là do sử dụng BindingProxy dựa trên tài nguyên và thứ tự tuyên truyền DataContext=null trên phân cấp điều khiển.

1

này 'Hack' làm việc cho tôi tạm thời, để buộc các sự kiện InotifyChanged, chỉ cần gán điều khiển mà lại riêng của nó Nội dung. Thực hiện điều này trước khi đánh giá hàm liên kết của hàm HasError. Ví dụ một textbox sẽ là:

((TextBox)child).Text = ((TextBox)child).Text; 

Và sau đó là một ví dụ hoàn chỉnh (trước khi tôi nghe đây không phải là MVVM đúng, tôi trực tiếp nhận được xử lý trên lưới để dễ trình bày mã snipet này)

 public bool Validate() 
    {   
     bool hasErr = false; 

     for (int i = 0; i != VisualTreeHelper.GetChildrenCount(grd); ++i) 
     { 
      DependencyObject child = VisualTreeHelper.GetChild(grd, i); 
      if (child is TextBox) 
      { 
       bool pp = BindingOperations.IsDataBound(child, TextBox.TextProperty); 
       if (pp) 
       { 

        ((TextBox)child).Text = ((TextBox)child).Text; 

        hasErr = BindingOperations.GetBindingExpression(child, TextBox.TextProperty).HasError; 
        System.Collections.ObjectModel.ReadOnlyCollection<ValidationError> errors = BindingOperations.GetBindingExpression(child, TextBox.TextProperty).ValidationErrors; 
        if (hasErr) 
        { 
         main.BottomText.Foreground = Brushes.Red; 
         main.BottomText.Text = BindingOperations.GetBinding(child, TextBox.TextProperty).Path.Path.Replace('.', ' ') + ": " + errors[0].ErrorContent.ToString(); 
         return false; 
        } 
       } 
      } 
      if (child is DatePicker) 
      { 
       ...      
      } 
     } 

     return true; 
    } 
Các vấn đề liên quan