Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WPF UpdateSourceTrigger

I have a TextBox which is bound to a property and I've set its UpdateSourceTrigger Property as Explicit so that I can control when it validates. However, as soon as the UI loads the control validates. I never call the UpdateSource method for the binding from the code behind. I'm not sure why this is happening but I do not know how to fix it.

Is there a reason why UpdateSourceTrigger="Explicit" is not working?

Please help! Thanks!

Edit: Initially the TextBox is empty which, when validated, causes a validation error. I want to avoid this. I want to validate explicitly only when the textbox loses focus or I click a validate button. Now, if I understand this correctly, all I need to do is call the UpdateSource method for the BindingExpression in the TextBox_LostFocus handler and the Click event handler for the button. However, I can't figure out how to avoid the initial validation, or avoid validation until I hit that TextBox. I've used a workaround(which I dislike) but I would prefer to find a better way of doing this.

I am using MVVM, yes. Thank you for the explanation! It's very helpful.

Further Edit: Yes, I'm using IDataErrorInfo

like image 937
Duke Cyrillus Avatar asked Feb 19 '23 06:02

Duke Cyrillus


1 Answers

That's normal behaviour.

The binding expression specified in your DependencyProperty (i.e. Text in this case) will do an initial bind when the element is initialized/loaded (and Update the Target from the Source...i.e. the Text property of your TextBox is set to the value in the property in your Source with the specified Path (n.b. ignore the case where a Path isn't specified for now)).

UpdateSourceTrigger="Explicit" just stops the automatic update of the value in the Target (i.e. the Text property of your TextBox) from being sent to your Source (e.g. a ViewModel/model) .... (don't confuse this option with controlling the Update of the Target).

During the initial bind I'd imagine that the binding engine sees that the "source" has an IDataErrorInfo and so it checks if the "item" is valid...and if not...you get the standard error adorner surrounding your TextBox (defined by an ErrorTemplate) ....so that it matches the state of the data in your model....that's all logical.

To stop the error indicators being shown too aggressively after the initial loading of your view...you could try this workaround.

You could change your IDataErrorInfo so that you are in control of when it will perform the validation checking logic.

Have a flag that gets set after the view has been loaded...which allows the IDataErrorInfo validation code to be run...and not before.

Once loaded from that point on, calls to UpdateSource will fire the Validator which will catch invalid data (because your Loaded flag will be true, and your validation logic will do it's magic).

You could use something like this:

public class CustomerViewModel : IDataErrorInfo
{
    public bool DoValidation { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }

    public string Error
    {
        get
        {
            if (DoValidation)
            {
                if (error on any properties)
                     return "error on these .....";
            }
            return null; // no errors
        }
    }

    public string this[string columnName]
    {
        get
        {
            if (!DoValidation)
            {
                return null; 
            }

            string result = null;
            if (columnName == "FirstName")
            {
                if (string.IsNullOrEmpty(FirstName))
                    result = "Please enter a First Name";
            }
            if (columnName == "LastName")
            {
                if (string.IsNullOrEmpty(LastName))
                    result = "Please enter a Last Name";
            }

            return result;
        }
    }
}

Set the DoValidation property on the model after the Loaded event has occurred.

like image 87
CSmith Avatar answered Feb 27 '23 19:02

CSmith