2011-02-18 59 views
1

我一直在開發從Decorator繼承的ErrorProvider控件。它驗證控件中綁定到某個元素的任何元素。它循環遍歷每個綁定和一個FrameworkElement,並向綁定的ValidationRules添加一個ExceptionValidationRule和一個DataErrorValidation。將ExceptionValidationRule添加到代碼中的綁定中

這是做工作的方法:

Private Sub ApplyValidationRulesToBindings() 
    Dim bindings As Dictionary(Of FrameworkElement, List(Of Binding)) = GetBindings() 

    For Each felement In bindings.Keys 
     Dim knownBindings As List(Of Binding) = bindings(felement) 

     For Each knownBinding As Binding In knownBindings 
      'Applying Exception and Data Error validation rules' 
      knownBinding.ValidationRules.Add(New ExceptionValidationRule()) 
      knownBinding.ValidationRules.Add(New DataErrorValidationRule()) 
     Next 

    Next 
End Sub 

顯然,DataErrorValidationRule應用到綁定,但ExceptionValidationRule不是。

有誰知道爲什麼這可能是這種情況?

編輯: 好了,多了幾分對這個問題的信息。

我一直在閱讀噸驗證和綁定類的MSDN文檔。 Binding.UpdateSourceExceptionFilter Property允許您指定一個函數,該函數處理綁定上發生的任何異常(如果ExceptionValidationRule已與綁定關聯)。

我爲UpdateSourceExceptionFilter屬性添加了一個方法,並猜測是什麼!它被執行了。但!!儘管我返回了異常,但是ValidationError對象並沒有被添加到綁定元素的Validation.Errors集合中,即使MSDN文檔說它是...

我註釋掉了動態添加ExceptionValidationRule的代碼手動添加到一個在XAML像這樣結合:

<TextBox HorizontalAlignment="Left" Name="TextBox1" VerticalAlignment="Top" 
            Width="200"> 
    <TextBox.Text> 
    <Binding Path="Name"> 
     <Binding.ValidationRules> 
     <ExceptionValidationRule /> 
     </Binding.ValidationRules> 
    </Binding> 
    </TextBox.Text> 
</TextBox> 

被執行的UpdateSourceException方法(我沒有改變它),並加入誤差到Validation.Errors作爲MSDN說明。

什麼是好奇這整件事的事實ExceptionValidationRule其實加入到通過VB.NET代碼完成時(否則的UpdateSourceException就不會執行)綁定;但是,Validate.Errors不會更新與錯誤。

如前所述,DataErrorValidationRule被添加到綁定並正常工作......我只是有ExceptionValidationRule的問題。

我的解決方案:

事實證明,我只好打電話給BindingOperations.SetBinding Method的約束力和屬性來驗證規則適用於具有約束力。我沒有辦法檢索DependencyProperty,這個DependencyProperty對於我的ApplyValidationRulesToBindings方法中的元素/綁定,所以我移動了將規則應用於回調方法的代碼,提供了我的方法來遞歸地檢索所有的綁定。

這裏是我的解決方案:

''' <summary>' 
''' Gets and returns a list of all bindings. ' 
''' </summary>' 
''' <returns>A list of all known bindings.</returns>' 
Private Function GetBindings() As Dictionary(Of FrameworkElement, List(Of Binding)) 
    If _bindings Is Nothing OrElse _bindings.Count = 0 Then 
     _bindings = New Dictionary(Of FrameworkElement, List(Of Binding)) 
     FindBindingsRecursively(Me.Parent, AddressOf RetrieveBindings) 
    End If 
    Return _bindings 
End Function 


''' <summary>' 
''' Recursively goes through the control tree, looking for bindings on the current data context.' 
''' </summary>' 
''' <param name="element">The root element to start searching at.</param>' 
''' <param name="callbackDelegate">A delegate called when a binding if found.</param>' 
Private Sub FindBindingsRecursively(ByVal element As DependencyObject, ByVal callbackDelegate As FoundBindingCallbackDelegate) 

    ' See if we should display the errors on this element' 
    Dim members As MemberInfo() = element.[GetType]().GetMembers(BindingFlags.[Static] Or BindingFlags.[Public] Or BindingFlags.FlattenHierarchy) 

    For Each member As MemberInfo In members 
     Dim dp As DependencyProperty = Nothing 
     ' Check to see if the field or property we were given is a dependency property' 
     If member.MemberType = MemberTypes.Field Then 
      Dim field As FieldInfo = DirectCast(member, FieldInfo) 
      If GetType(DependencyProperty).IsAssignableFrom(field.FieldType) Then 
       dp = DirectCast(field.GetValue(element), DependencyProperty) 
      End If 
     ElseIf member.MemberType = MemberTypes.[Property] Then 
      Dim prop As PropertyInfo = DirectCast(member, PropertyInfo) 
      If GetType(DependencyProperty).IsAssignableFrom(prop.PropertyType) Then 
       dp = DirectCast(prop.GetValue(element, Nothing), DependencyProperty) 
      End If 

     End If 
     If dp IsNot Nothing Then 
      ' we have a dependency property. ' 
      'Checking if it has a binding and if so, checking if it is bound to the property we are interested in' 
      Dim bb As Binding = BindingOperations.GetBinding(element, dp) 
      If bb IsNot Nothing Then 
       ' This element has a DependencyProperty that we know of that is bound to the property we are interested in. ' 
       ' Passing the information to the call back method so that the caller can handle it.' 
       If TypeOf element Is FrameworkElement Then 
        If Me.DataContext IsNot Nothing AndAlso DirectCast(element, FrameworkElement).DataContext IsNot Nothing Then 
         callbackDelegate(DirectCast(element, FrameworkElement), bb, dp) 
        End If 
       End If 
      End If 
     End If 
    Next 

    'Recursing through any child elements' 
    If TypeOf element Is FrameworkElement OrElse TypeOf element Is FrameworkContentElement Then 
     For Each childElement As Object In LogicalTreeHelper.GetChildren(element) 
      If TypeOf childElement Is DependencyObject Then 
       FindBindingsRecursively(DirectCast(childElement, DependencyObject), callbackDelegate) 
      End If 
     Next 
    End If 
End Sub 

''' <summary>' 
''' Called when recursively populating the Bindings dictionary with FrameworkElements(key) and their corresponding list of Bindings(value)' 
''' </summary>' 
''' <param name="element">The element the binding belongs to</param>' 
''' <param name="binding">The Binding that belongs to the element</param>' 
''' <param name="dp">The DependencyProperty that the binding is bound to</param>' 
''' <remarks></remarks>' 
Sub RetrieveBindings(ByVal element As FrameworkElement, ByVal binding As Binding, ByVal dp As DependencyProperty) 
    'Applying an exception validation and data error validation rules to the binding' 
    'to ensure that validation occurs for the element' 
    If binding.ValidationRules.ToList.Find(Function(x) GetType(ExceptionValidationRule) Is (x.GetType)) Is Nothing Then 
     binding.ValidationRules.Add(New ExceptionValidationRule()) 
     binding.ValidationRules.Add(New DataErrorValidationRule()) 
     binding.UpdateSourceExceptionFilter = New UpdateSourceExceptionFilterCallback(AddressOf ReturnExceptionHandler) 
     'Resetting the binding to include the validation rules just added' 
     BindingOperations.SetBinding(element, dp, binding) 
    End If 

    ' Remember this bound element. This is used to display error messages for each property.' 
    If _bindings.ContainsKey(element) Then 
     DirectCast(_bindings(element), List(Of Binding)).Add(binding) 
    Else 
     _bindings.Add(element, New List(Of Binding)({binding})) 
    End If 
End Sub 

謝謝!

-Frinny

回答

2

我真的不以下怎樣你的代碼的作品,但你不能修改已經使用後綁定,所以你不能添加ValidationRule s到現有綁定。我想你必須複製綁定,屬性屬性,然後添加ValidationRule s,然後將新複製的綁定設置爲BindingOperations.SetBinding(...)

另一種方法可以創建自己的子類的結合,其中添加的ValidationRule小號直接例如

public class ExBinding : Binding 
{ 
    public ExBinding() 
    { 
     NotifyOnValidationError = true; 
     ValidationRules.Add(new ExceptionValidationRule()); 
     ValidationRules.Add(new DataErrorValidationRule()); 
    } 
} 

可用像

<TextBox Text="{local:ExBinding Path=MyProperty}"/> 

更新

我不認爲你明白我的答案。您無法修改綁定,因爲您正在嘗試執行的操作不起作用。這是一個C#示例應用程序,它顯示了這一點。它包含三個TextBox S其中

  • 首先TextBox增加與ExceptionValidationRule綁定在XAML
  • TextBox增加在XAML綁定,並增加了ExceptionValidationRule在其加載的事件
  • TextBox增加與綁定ExceptionValidationRule在Loaded事件

的ExceptionValidationRule會爲TextBox 1和3,但沒有工作了2.上傳樣本這裏:http://www.mediafire.com/?venm09dy66q4rmq

更新2
你可以得到這個,如果你設置你已經添加了驗證規則後像

BindingExpression bindingExpression = textBox.GetBindingExpression(TextBox.TextProperty); 
Binding textBinding = bindingExpression.ParentBinding; 
textBinding.ValidationRules.Add(new ExceptionValidationRule()); 
// Set the Binding again after the `ExceptionValidationRule` has been added 
BindingOperations.SetBinding(textBox, TextBox.TextProperty, textBinding); 

再次綁定我不上班知道如何你GetBindings方法的樣子,但也許你可以添加一個SetBindings方法,你重新設置綁定和調用這個方法您已經添加了ExceptionValidationRule小號

+0

我已經通過該建議THI線程讀取之後秒。 – Frinavale 2011-02-18 21:09:04