IDataErrorInfo - Initially ignore the errors when view is first loaded
Asked Answered
D

4

13

I am trying to validate my model class using IDataErrorInfo as given below.

//Validators
public string this[string propertyName] {
    get {
        string error = null;

        if (propertyName == "Name") {
            error = ValidateName(); 
        }
        return error;
    }
}

This works fine, except that when the view first loads it already contains validation errors. Is it possible to ignore/suppress validation errors when the view is first loaded. Also, is it a common practice to show errors when the view loads and before the User starts the data entry for the model properties.

regards, Nirvan.

Edit: This is how I am setting up IDataErrorInfo.

<TextBox Text="{Binding Name, ValidatesOnDataErrors=True}" Grid.Row="1" Grid.Column="1" />
Danidania answered 17/4, 2012 at 11:15 Comment(2)
See this question: #1502763Tolerance
@AlexKofman mark this question as dupplicate. I have already done it.Cally
D
3

I have took the following approach and it works. Basically, the Model should rightfully record errors and have them listed up in a dictionary, even if the object is just instantiated and User hasn't entered any Text yet. So I didn't change my Model code or the IDataErrorInfo validation code. Instead, I just set the Validation.Error Template property to {x:Null} initially. Then there is code to wire up the TextBox's LostFocus event that changes the Validation.Error template back to what I am using. In order to achieve the swapping of templates and attaching LostFocus event handler to all TextBox's in my application, I used a couple of dependency properties. Here is the code that I have used.

Dependency Properties and LostFocus Code:

    public static DependencyProperty IsDirtyEnabledProperty = DependencyProperty.RegisterAttached("IsDirtyEnabled",
             typeof(bool), typeof(TextBoxExtensions), new PropertyMetadata(false, OnIsDirtyEnabledChanged));
    public static bool GetIsDirtyEnabled(TextBox target) {return (bool)target.GetValue(IsDirtyEnabledProperty);}
    public static void SetIsDirtyEnabled(TextBox target, bool value) {target.SetValue(IsDirtyEnabledProperty, value);}

    public static DependencyProperty ShowErrorTemplateProperty = DependencyProperty.RegisterAttached("ShowErrorTemplate",
             typeof(bool), typeof(TextBoxExtensions), new PropertyMetadata(false));
    public static bool GetShowErrorTemplate(TextBox target) { return (bool)target.GetValue(ShowErrorTemplateProperty); }
    public static void SetShowErrorTemplate(TextBox target, bool value) { target.SetValue(ShowErrorTemplateProperty, value); }

    private static void OnIsDirtyEnabledChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs args) {
        TextBox textBox = (TextBox)dependencyObject;
        if (textBox != null) {
            textBox.LostFocus += (s, e) => {
                if ((bool) textBox.GetValue(ShowErrorTemplateProperty) == false) {
                    textBox.SetValue(ShowErrorTemplateProperty, true);
                }
            };
        }
    }

If IsDirtyEnabled dependency property is set to true, it uses the callback to attach the TextBox's LostFocus event to a handler. The handler just changes the ShowErrorTemplate attached property to true, which in turn triggers in textbox's style trigger to show the Validation.Error template, when the TextBox loses focus.

TextBox Styles:

<Style TargetType="{x:Type TextBox}">
    <Setter Property="Validation.ErrorTemplate" Value="{StaticResource ValidationErrorTemplate}"/>
    <Setter Property="gs:TextBoxExtensions.IsDirtyEnabled" Value="True" />
    <Style.Triggers>
        <Trigger Property="gs:TextBoxExtensions.ShowErrorTemplate" Value="false">
            <Setter Property="Validation.ErrorTemplate" Value="{x:Null}"/>
        </Trigger>
    </Style.Triggers>
</Style>

This may seem too much of code for a simple thing, but then I have to do it only once for all the Textboxes I am using.

regards, Nirvan.

Danidania answered 19/4, 2012 at 12:57 Comment(2)
Nirvan's solution does the trick, if you move this code to a base class (BaseControll for example) than you can derive all your controls from this base class and have this behaviour in all your controls.Oscaroscillate
I know it's been a while but I'm facing the same issue. Your solution works perfectly, my question is whether the validation error message is the same for all fields--the error template points to a static resource--thanks!Boehike
R
2

try to set the data context AFTER the view has been shown.

In my case, this helped.

Rebut answered 6/8, 2012 at 7:30 Comment(0)
M
1

Are you throwing the exception in the get?

public string Name
{
    get { return _name; }
    set
    {
        _name = value;
        if (String.IsNullOrEmpty(value))
        {
            throw new ApplicationException("Customer name is mandatory.");
        }
    }
}
Mcloughlin answered 17/4, 2012 at 12:19 Comment(3)
No, I am not throwing any exceptions. I am using IDataErrorInfo interface to validate model properties.Danidania
My recollection is I had to use ValidationRules to get error checking only on the set. Sorry I don't have access that code right now.Mcloughlin
Thanks for your effort anyway.Danidania
E
1

you set the rules in your ValidateName() method. your view just show the error :) i suggest that name is a mandatory field and should be filled by the user but you dont like the red border when the view is first loaded?

i use two different control templates for validation.errortemplate the normal one and one for mandatory fields (a red *)

thats the way i did it the last time.

Evacuate answered 17/4, 2012 at 13:18 Comment(1)
That would certainly hide the error in the view and could be a possible solution. However, I will still wait for some time in case there is a better solution than this one. ThanksDanidania

© 2022 - 2024 — McMap. All rights reserved.