2010-06-30 40 views
7

Tôi có một WPF UserControl với nhiều điều khiển khác bên trong nó. Hộp văn bản nằm trong số này. Mỗi TextBox có xác nhận của riêng mình:Xác thực WPF: Xóa tất cả các lỗi xác thực

<TextBox> 
    <TextBox.Text> 
     <Binding Path="MyPath" StringFormat="{}{0:N}" NotifyOnValidationError="True"> 
      <Binding.ValidationRules> 
       <r:MyValidationRule ValidationType="decimal" /> 
      </Binding.ValidationRules> 
     </Binding> 
    <TextBox.Text> 
<TextBox> 

một

Bây giờ giả sử các loại sử dụng một số ký tự không hợp lệ vào chúng. Tất cả chúng sẽ trở nên nổi bật màu đỏ.

Bây giờ tôi muốn đặt lại tất cả các lỗi xác nhận (từ đầu vào không chính xác) và thiết lập các giá trị đúng gần đây đến từ DataContext.

Tôi đặt DataContext trong constructor và tôi không muốn thay đổi nó (DataContext = null sẽ không giúp tôi rồi):

DataContext = _myDataContext = new MyDataContext(..); 

Những gì tôi đã tìm thấy là các lớp:

Validation.ClearInvalid(..) 
BindingExpression.UpdateTarget(); 

Tôi nghĩ rằng các lớp này có thể giúp tôi, nhưng chúng yêu cầu Binding của bê tông FrameworkElement và tôi muốn làm điều đó trên toàn cầu cho tất cả chúng.

Tôi có nên lặp lại thông qua Visual Tree (đây thực sự là điều tôi không thích) hoặc có giải pháp nào tốt hơn cho điều này không?

+0

Khi bạn ràng buộc các giá trị chính xác, sau đó tự động, nó sẽ đặt lại các lỗi xác thực.Bạn đang sử dụng giao diện INotifyPropertyChanged cho viewmodel & Property của bạn sẽ tăng sự kiện đã thay đổi thuộc tính? – Ragunathan

+0

Có, tôi đang sử dụng nó .. đó là những gì tôi đã thử lúc đầu. Nhưng không có thay đổi trong DataSource. Vì vậy, WPF sẽ không phản ánh giá trị cũ –

Trả lời

2

Đây là những gì một BindingGroup là dành cho ... Bạn muốn thiết lập một BindingGroup trên một container của tất cả các kiểm soát, ví dụ bảng điều khiển chứa chúng. Điều này sẽ gây ra các bản cập nhật cho DataContext được giữ cho đến khi bạn gọi UpdateSources trên BindingGroup. Nếu bạn muốn đặt lại đầu vào của người dùng, bạn sẽ gọi CancelEdit và BindingGroup sẽ đặt lại tất cả các điều khiển bên trong vùng chứa thành các giá trị (vẫn không thay đổi) của DataContext.

1

Tại sao bạn không kích hoạt NotifyPropertyChanged cho tất cả các thuộc tính của nguồn dữ liệu của bạn? Điều này sẽ cập nhật các ràng buộc và điều khiển giao diện người dùng sẽ nhận được các giá trị từ datacontext (có giá trị, do đó các lỗi xác nhận sẽ bị xóa)?

+0

Nope .. Tôi đã thử điều này như là đầu tiên .. nó không hoạt động: -/ –

+0

Oh, có nó, nó hoạt động cho tôi vì tôi sử dụng tùy chọn ValidatesOnExceptions và ném trường hợp ngoại lệ xác nhận trong người định cư. Vì vậy, các giá trị ban đầu (hợp lệ) không được overriden với không hợp lệ. – Andrii

0

Tôi không chắc chắn những gì bạn có ý nghĩa bởi

Tôi đặt DataContext trong constructor và tôi không muốn thay đổi nó (DataContext = null sẽ không giúp tôi rồi)

Nói chung để thiết lập lại tất cả các cam kết ràng buộc về hình thức bạn thực hiện như sau: (giả sử một bộ điều khiển cho views/dây viewmodel, nếu không chỉ cần sử dụng một mã-đằng sau trên quan điểm.)

var dataContext = view.DataContext; 
view.DataContext = null; 
view.DataContext = dataContext; 

Nó không thay đổi nó thành ngữ cảnh dữ liệu mới, nó chỉ làm giảm ngữ cảnh dữ liệu và tải lại nó. Điều này khởi động tất cả các ràng buộc để tải lại.

1

Tôi gặp vấn đề tương tự. Nhiều điều khiển được xác thực trên một trang. Tôi tìm thấy/làm giải pháp này để cập nhật (và xóa tất cả các xác nhận từ) descentents của một DependencyObject:

using System.Linq; 
using System.Windows; 
using System.Windows.Data; 
using System.Windows.Media; 

/// <summary> 
/// Updates all binding targets where the data item is of the specified type. 
/// </summary> 
/// <param name="root">The root.</param> 
/// <param name="depth">The depth.</param> 
/// <param name="dataItemType">Type of the data item.</param> 
/// <param name="clearInvalid">Clear validation errors from binding.</param> 
public static void UpdateAllBindingTargets(this DependencyObject root, int depth, Type dataItemType, bool clearInvalid) 
{ 
    var bindingExpressions = EnumerateDescendentsBindingExpressions(root, depth); 
    foreach (BindingExpression be in bindingExpressions.Where(be => be.DataItem != null && be.DataItem.GetType() == dataItemType)) 
    { 
     if (be != null) 
     { 
      be.UpdateTarget(); 
      if (clearInvalid) 
       System.Windows.Controls.Validation.ClearInvalid(be); 
     } 
    } 
} 

/// <summary> 
/// Enumerates all binding expressions on descendents. 
/// </summary> 
/// <param name="root">The root.</param> 
/// <param name="depth">The depth.</param> 
/// <returns></returns> 
public static IEnumerable<BindingExpression> EnumerateDescendentsBindingExpressions(this DependencyObject root, int depth) 
{ 
    return root.EnumerateDescendents(depth).SelectMany(obj => obj.EnumerateBindingExpressions()); 
} 

/// <summary> 
/// Enumerates the descendents of the specified root to the specified depth. 
/// </summary> 
/// <param name="root">The root.</param> 
/// <param name="depth">The depth.</param> 
public static IEnumerable<DependencyObject> EnumerateDescendents(this DependencyObject root, int depth) 
{ 
    int count = VisualTreeHelper.GetChildrenCount(root); 
    for (int i = 0; i < count; i++) 
    { 
     var child = VisualTreeHelper.GetChild(root, i); 
     yield return child; 
     if (depth > 0) 
     { 
      foreach (var descendent in EnumerateDescendents(child, --depth)) 
       yield return descendent; 
     } 
    } 
} 

/// <summary> 
/// Enumerates the binding expressions of a Dependency Object. 
/// </summary> 
/// <param name="element">The parent element.</param> 
public static IEnumerable<BindingExpression> EnumerateBindingExpressions(this DependencyObject element) 
{ 
    if (element == null) 
    { 
     throw new ArgumentNullException("element"); 
    } 

    LocalValueEnumerator lve = element.GetLocalValueEnumerator(); 

    while (lve.MoveNext()) 
    { 
     LocalValueEntry entry = lve.Current; 

     if (BindingOperations.IsDataBound(element, entry.Property)) 
     { 
      if (entry.Value is PriorityBindingExpression) 
      { 
       foreach (BindingExpression expr in ((PriorityBindingExpression)entry.Value).BindingExpressions) 
        yield return expr; 
      } 
      else if (entry.Value is MultiBindingExpression) 
      { 
       foreach (BindingExpression expr in ((MultiBindingExpression)entry.Value).BindingExpressions) 
        yield return expr; 
      } 
      else 
       yield return entry.Value as BindingExpression; 
     } 
    } 
} 
Các vấn đề liên quan