2009-06-25 72 views
2

如果FirstName值爲null或空,並且我試圖在作爲ErrorTemplate一部分的TextBlock中顯示錯誤消息,那麼我將拋出ApplicationException。但它總是顯示「異常已被引發到調用目標」。WPF ExceptionValidationRule不在Validation.Errors集合中顯示

public string FirstName 
     { 
      get { return _firstName;} 
      set 
      { 
       if(String.IsNullOrEmpty(value)) 
        throw new ApplicationException("FirstName cannot be null or empty!"); 
       _firstName = value; 

       OnPropertyChanged("FirstName"); 
      } 
     } 

<Style x:Key="TextBoxStyle" TargetType="TextBox"> 

      <Setter Property="Validation.ErrorTemplate"> 
       <Setter.Value> 
        <ControlTemplate> 
         <DockPanel LastChildFill="True"> 
          <TextBlock DockPanel.Dock="Right" 
         Foreground="Orange" 
         FontSize="12pt" 
         Text="{Binding ElementName=MyAdorner, Path=AdornedElement.(Validation.Errors)[0].ErrorContent}"> 
          </TextBlock> 
          <Border BorderBrush="Green" BorderThickness="1"> 
           <AdornedElementPlaceholder Name="MyAdorner" /> 
          </Border> 
         </DockPanel> 
        </ControlTemplate> 
       </Setter.Value> 
      </Setter> 

     </Style> 

最後這裏是TextBox控件:

<TextBox Name="txtFirstName" Style="{StaticResource TextBoxStyle}" Grid.Column="1" Grid.Row="0" Height="20" Width="100" Margin="10"> 
       <TextBox.Text> 
        <Binding Path="FirstName"> 
         <Binding.ValidationRules> 
          <ExceptionValidationRule /> 
         </Binding.ValidationRules> 
        </Binding> 
       </TextBox.Text> 

      </TextBox> 

回答

5

我通過這個去的那天,我最終採取異常關閉的財產和使用驗證類。

<TextBox Name="txtFirstName" Style="{StaticResource TextBoxStyle}" Grid.Column="1" Grid.Row="0" Height="20" Width="100" Margin="10"> 
     <TextBox.Text> 
      <Binding Path="FirstName" > 
       <Binding.ValidationRules> 
        <validators:StringRangeValidationRule 
            MinimumLength="1" 
            MaximumLength="40" 
            ErrorMessage="Required" /> 
       </Binding.ValidationRules> 
      </Binding> 
     </TextBox.Text> 

從屬性中刪除異常所以它只是看起來像這樣...

private string _firstName; 
    public string FirstName 
    { 
     get { return _firstName; } 
     set 
     { 
      _firstName = value; 

      OnPropertyChanged("FirstName"); 
     } 
    } 

繼承人的驗證類(我這個挖走了互聯網某處)...

public class StringRangeValidationRule : ValidationRule 
{ 
    private int _minimumLength = -1; 
    private int _maximumLength = -1; 
    private string _errorMessage; 

    public int MinimumLength 
    { 
     get { return _minimumLength; } 
     set { _minimumLength = value; } 
    } 

    public int MaximumLength 
    { 
     get { return _maximumLength; } 
     set { _maximumLength = value; } 
    } 

    public string ErrorMessage 
    { 
     get { return _errorMessage; } 
     set { _errorMessage = value; } 
    } 

    public override ValidationResult Validate(object value, 
     CultureInfo cultureInfo) 
    { 
     ValidationResult result = new ValidationResult(true, null); 
     string inputString = (value ?? string.Empty).ToString(); 
     if (inputString.Length < this.MinimumLength || 
       (this.MaximumLength > 0 && 
       inputString.Length > this.MaximumLength)) 
     { 
      result = new ValidationResult(false, this.ErrorMessage); 
     } 
     return result; 
    } 
} 

您需要在xaml中添加一個名稱空間引用,以將驗證類所在的位置所謂的驗證程序(我敢肯定,你知道這一點,但只是爲了完整性)

喜歡的東西...

xmlns:validators="clr-namespace:WpfApplication1" 

希望這有助於!

乾杯,

安迪

+0

謝謝,確實工作。還有一個問題!如果我在TextBox中輸入某些內容,然後將其刪除,然後從TextBox中丟失焦點,則驗證將觸發。無論如何,當文本框爲空並且失去焦點時,會觸發驗證。 – azamsharp 2009-06-26 14:51:48

3

同樣,我有過一樣的事情這星期過去了!我在網上找到了下面,包裹你的文本框在此...

<validators:ValidatedContent Name="Validator" > 

<!-- All your textboxes here --> 

</validators:ValidatedContent> 

添加下面的類中,你把對方一個相同的地方......然後,你可以調用Validator.Validate()從按鈕點擊或任何你想要的地方。還有,你是否要保存等

public class ValidatedContent : Decorator 
{ 

    #region Public Constructors 

    /// <summary> 
    /// Initializes a new instance of ValidatedContent 
    /// </summary> 
    public ValidatedContent() 
    { 
     ErrorMessages = new ObservableCollection<string>(); 

     Loaded += new RoutedEventHandler(OnValidatedContentLoaded); 
    } 

    #endregion 

    #region Event Handlers 

    /// <summary> 
    /// Handles the loaded event 
    /// </summary> 
    /// <param name="sender"></param> 
    /// <param name="e"></param> 
    private void OnValidatedContentLoaded(object sender, RoutedEventArgs e) 
    { 
     Queue<DependencyObject> elementQueue = new Queue<DependencyObject>(); 
     elementQueue.Enqueue(this.Child); 

     // Iterate over all the child elements 
     while (elementQueue.Count > 0) 
     { 
      // Dequeue the first element in the queue 
      DependencyObject element = elementQueue.Dequeue(); 

      if (element != null) 
      { 
       foreach (var childElement in LogicalTreeHelper.GetChildren(element)) 
       { 
        if (childElement is DependencyObject) 
         elementQueue.Enqueue((DependencyObject)childElement); 
       } 
      } 

      Control control = element as Control; 

      // Mark the element as valid if it is a control 
      if (control != null && GetIsRequired(element)) 
      { 
       control.SetValue(Control.StyleProperty, RequiredControlStyle); 
      } 
     } 

    } 

    #endregion 

    #region Dependency Properties 

    public static readonly DependencyProperty IsContentValidProperty = 
     DependencyProperty.Register("IsContentValid", typeof(bool), 
     typeof(ValidatedContent), new UIPropertyMetadata(false)); 

    public static readonly DependencyProperty ErrorMessagesProperty = 
     DependencyProperty.Register("ErrorMessages", typeof(ObservableCollection<string>), 
     typeof(ValidatedContent), new UIPropertyMetadata(null)); 

    public static readonly DependencyProperty RequiredControlStyleProperty = 
     DependencyProperty.Register("RequiredControlStyle", typeof(Style), 
     typeof(ValidatedContent), new UIPropertyMetadata(null)); 

    public static readonly DependencyProperty IsRequiredProperty = 
     DependencyProperty.RegisterAttached("IsRequired", typeof(bool), 
     typeof(ValidatedContent), new UIPropertyMetadata(false)); 

    #endregion 

    #region Public Properties 

    /// <summary> 
    /// Gets or sets the style to mark a required control 
    /// </summary> 
    public Style RequiredControlStyle 
    { 
     get { return (Style)GetValue(RequiredControlStyleProperty); } 
     set { SetValue(RequiredControlStyleProperty, value); } 
    } 

    /// <summary> 
    /// Gets or sets the error messages for the validated content 
    /// </summary> 
    public ObservableCollection<string> ErrorMessages 
    { 
     get { return (ObservableCollection<string>)GetValue(ErrorMessagesProperty); } 
     private set { SetValue(ErrorMessagesProperty, value); } 
    } 

    /// <summary> 
    /// Gets if the content is valid 
    /// </summary> 
    public bool IsContentValid 
    { 
     get { return (bool)GetValue(IsContentValidProperty); } 
     private set { SetValue(IsContentValidProperty, value); } 
    } 

    #endregion 

    #region Public Methods 

    /// <summary> 
    /// Validates the content of the decorator 
    /// </summary> 
    public void Validate() 
    { 
     IsContentValid = true; 
     ErrorMessages.Clear(); 

     Queue<DependencyObject> elementQueue = new Queue<DependencyObject>(); 
     elementQueue.Enqueue(this.Child); 

     // Iterate over all the child elements 
     while (elementQueue.Count > 0) 
     { 
      // Dequeue the first element in the queue 
      DependencyObject element = elementQueue.Dequeue(); 


      foreach (var childElement in LogicalTreeHelper.GetChildren(element)) 
      { 
       if (childElement is DependencyObject) 
        elementQueue.Enqueue((DependencyObject)childElement); 
      } 


      // Validate the bindings of the element 
      ValidateBindings(element); 
     } 
    } 

    #endregion 

    #region Private Methods 

    /// <summary> 
    /// Validates the bindings of the dependency object 
    /// </summary> 
    /// <param name="element"></param> 
    private void ValidateBindings(DependencyObject element) 
    { 
     if (element != null) 
     { 
      Type elementType = element.GetType(); 

      FieldInfo[] dependencyPropertyFields = elementType.GetFields(
       BindingFlags.Static | BindingFlags.Public | BindingFlags.DeclaredOnly); 

      // Iterate over all dependency properties 
      foreach (FieldInfo dependencyPropertyField in dependencyPropertyFields) 
      { 
       DependencyProperty dependencyProperty = 
        dependencyPropertyField.GetValue(element) as DependencyProperty; 

       if (dependencyProperty != null) 
       { 
        Binding binding = BindingOperations.GetBinding(element, dependencyProperty); 
        BindingExpression bindingExpression = BindingOperations.GetBindingExpression(element, dependencyProperty); 

        // Issue 1822 - Extra check added to prevent null reference exceptions 
        if (binding != null && bindingExpression != null) 
        { 
         // Validate the validation rules of the binding 
         foreach (ValidationRule rule in binding.ValidationRules) 
         { 
          ValidationResult result = rule.Validate(element.GetValue(dependencyProperty), 
           CultureInfo.CurrentCulture); 

          bindingExpression.UpdateSource(); 

          if (!result.IsValid) 
          { 
           ErrorMessages.Add(result.ErrorContent.ToString()); 
          } 

          IsContentValid &= result.IsValid; 
         } 
        } 
       } 
      } 
     } 
    } 

    #endregion 

    #region Static Methods 

    /// <summary> 
    /// Gets the value for the IsRequired attached property 
    /// </summary> 
    /// <param name="obj"></param> 
    /// <returns></returns> 
    public static bool GetIsRequired(DependencyObject obj) 
    { 
     return (bool)obj.GetValue(IsRequiredProperty); 
    } 

    /// <summary> 
    /// Sets the value for the IsRequired attached property 
    /// </summary> 
    /// <param name="obj"></param> 
    /// <param name="value"></param> 
    public static void SetIsRequired(DependencyObject obj, bool value) 
    { 
     obj.SetValue(IsRequiredProperty, value); 
    } 

    #endregion 
} 
+0

謝謝! 我正在創建用戶控件來處理驗證。像RequiredTextBox控件,RegularExpressionTextBox等。 – azamsharp 2009-06-26 16:18:01

0

我有這樣一些問題,也因此我張貼我的解決辦法的情況下,它會幫助別人,你可以用它來決定的IsContentValid財產。 由於在代碼中觸發的異常被封裝到TargetInvocationException中,因此Text塊中顯示的消息不正確。因此,顯示的錯誤消息是「異常已被引發到調用目標」的異常之一。

要顯示的例外是在TargetInvocationException的的InnerException實際提供服務,因此你可以使用下面的語句在你的XAML

Text="{Binding ElementName=MyAdorner, Path=AdornedElement.(Validation.Errors)[0].ErrorContent.InnerException.Message}" 

我敢肯定它顯示的消息,必須有一種方式,包含在ErrorContent字段中的錯誤是正確的,但我還沒有深入瞭解如何進行挖掘。