WPF ExceptionValidationRule не отображается в коллекции Validation.Errors - PullRequest
2 голосов
/ 25 июня 2009

Я выбрасываю ApplicationException, если значение FirstName равно нулю или пусто, и я пытаюсь отобразить сообщение об ошибке в TextBlock, который является частью ErrorTemplate. Но это всегда показывает: «Исключение было брошено в цель вызова».

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>

Ответы [ 3 ]

5 голосов
/ 26 июня 2009

Я прошел через это на днях, в итоге я исключил исключение из свойства и использовал класс проверки.

<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"

Надеюсь, это поможет!

Приветствия

Andy

3 голосов
/ 26 июня 2009

Опять же, на этой неделе я прошел через то же самое! Я нашел следующее в Интернете, заверните текстовые поля в это ...

<validators:ValidatedContent Name="Validator" >

<!-- All your textboxes here -->

</validators:ValidatedContent>

Добавьте приведенный ниже класс в то же место, куда вы поместили другой ... и затем вы можете вызывать Validator.Validate () одним нажатием кнопки или где угодно. Существует также свойство IsContentValid, которое вы можете использовать, чтобы решить, хотите ли вы сохранить и т. Д.

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 голосов
/ 17 июня 2013

У меня тоже были некоторые проблемы с этим, поэтому я публикую свой обходной путь на случай, если он кому-нибудь поможет. Сообщение, отображаемое в блоке Text, не является правильным, поскольку исключение, которое вызывается в коде, помещается в исключение TargetInvocationException. Таким образом, отображаемое сообщение об ошибке - это одно из тех исключений, которое называется «Исключение было выдано в качестве цели вызова».

Исключение, которое вы хотите отобразить, фактически доступно в InnerException TargetInvocationException, и поэтому вы можете отобразить это сообщение, используя следующую инструкцию в вашем XAML

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

Я почти уверен, что должен быть способ, которым ошибка, содержащаяся в поле ErrorContent, является правильной, но я недостаточно выкопал, чтобы понять, как.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...