1

I'd like to know if it is possible to customize the ErrorContent property which can be accessed through the Validation.Errors collection when there is an exception validation problem.

As an example, suppose you have a source property of type int that is data-bound to the TextBox.Text property. If the user types a non-integer value into that TextBox, then an exception occurs, and the Validation.Errors collection will have an entry that contains an error message like this:

                                                  Exception Validation Message

I want to know if I can determine when an exception problem occurs and choose a new message, such as

"Please enter a positive integer specifying the number of digits (must be between 2 and 10)."


I do not believe the IDataErrorInfo interface will suffice in providing the information I want. This is because I have no way of returning an error message when there is an exception problem.

For those interested, I've implemented IDataErrorInfo similar as below:

string IDataErrorInfo.Error { get { return null; } }
string IDataErrorInfo.this[string property]
{
    get
    {
        string message = null;
        switch (property) {
        case "Digits":
            if (Digits < 2 || Digits > 10)
                message = "There must be between 2 and 10 digits.";
            break 
        }
        return message;
    }
}

In this instance, Digits is the int source property. In this implementation I have no way of obtaining the text input from the user (and thus cannot check if it can cast to an int). Simply, I can only specify an error message for when there are no exception problems (if the user types an out of range integer, the IDataErrorInfo message appears).

So, how can I tell WPF to use the quoted error message when there is a validation exception? According to MSDN, the Validation.Errors collection cannot be modified by the application (although that is what IDataErrorInfo does).


The XAML style for the TextBox in the above image follows:
<Style x:Key="ValidatedTextBoxStyle" TargetType="TextBox">
    <Style.Triggers>
        <Trigger Property="Validation.HasError" Value="True">
            <Setter Property="ToolTip" 
                 Value="{Binding RelativeSource={RelativeSource Self}, 
                 Path=(Validation.Errors)[0].ErrorContent}"/>
        </Trigger>
    </Style.Triggers>
</Style>
Nicholas Miller
  • 4,205
  • 2
  • 39
  • 62
  • 1
    eh, http://msdn.microsoft.com/en-us/library/ms753962(v=vs.110).aspx? – Kcvin Aug 14 '14 at 21:14
  • Hey NETscape, I'm came across that tutorial. I'll take another look at it to see if it helps out. Thanks. – Nicholas Miller Aug 15 '14 at 01:15
  • Also check out [How to implement INotifyDataErrorInfo in WPF 4.5?](http://stackoverflow.com/questions/9950128/how-to-implement-inotifydataerrorinfo-in-wpf-4-5). – Sheridan Aug 15 '14 at 10:49
  • @Netscape - Apparently, I can use the `ValidationRule` and `IDataErrorInfo` together. Although, to be honest, it is probably better to put `IDataErrorInfo`'s logic in the new rule. – Nicholas Miller Aug 15 '14 at 12:53
  • @Sheridan - Unfortunately, I'm working in .NET 4.0, so I cannot use `INotifyDataErrorInfo`. – Nicholas Miller Aug 15 '14 at 12:53

1 Answers1

0

As pointed out by NETscape, using a ValidationRule seems to be the best solution.

Instead of wrapping the validation logic inside of IDataErrorInfo, it can be moved to a custom ValidationRule.

Visit this MSDN Page for full details on how to implement a ValidationRule.


The reason why a ValidationRule solves the issue is because it provides a method for retrieving the inputted data as an Object. This means that you can check to see if the inputted data is able to cast into the desired data type. On the other hand, IDataErrorInfo only gives access to the property name that should be validated.

Below is the implementation for the original post's example using a ValidationRule:

public class DigitsRangeRule : ValidationRule
{
    public int Min { get; set; }
    public int Max { get; set; }

    public override ValidationResult Validate(object value, CultureInfo info)
    {
        int digits = 0;

        try
        {
            digits = Int32.Parse((string)value);
        }
        catch
        {
            return new ValidationResult(false, 
                "Please specify a valid number of digits.");
        }

        if (digits < Min || digits > Max)
        {
            return new ValidationResult(false, 
                String.Format("There must be between {0} and {1}" +
                " digits for detail numbers.", Min, Max));
        }

        return new ValidationResult(true, null);
    }
}

To implement your own custom ValidationRule, you must derive from System.Windows.Controls.ValidationRule, and override the Validate method.

That method is responsible for returning the result of your validation (whether or not it succeeds), and the success/failure is indicated by the returned ValidationResult object. Since the method provides the inputted data mentioned earlier, we check to see if it casts properly. If not, then we simply return a failing result with the desired message.

There are a few reasons that ValidationRule is good to use here.

  • First, it does not depend on the underlying source object, which greatly improves flexibility.
  • It allows you to perform more dynamic validation through the use of properties.

In the above snippet, there are two properties Min and Max which can be decided in XAML each time an instance of the DigitsRangeRule is used.

Here is how you instruct the TextBox.Text property to use the above rule above:

<TextBox MaxLength="2">
    <TextBox.Text>
        <Binding Path="SourceObject.DigitsProperty">
            <Binding.ValidationRules>
                <local:DigitsRangeRule Min="2" Max="10"/>
            </Binding.ValidationRules>
        </Binding>
    </TextBox.Text>
</TextBox>

In the XAML above, local refers to the namespace containing the DigitsRangeRule.

Note that when using the rule, we can specify values for the minimum and maximum accepted values for the number of digits. This is particularly helpful in the case you have multiple TextBoxes that need different validation. You can specify instance-specific rules, without needing to write more code.

Nicholas Miller
  • 4,205
  • 2
  • 39
  • 62