Data Validation in WinForms with the ErrorProvider component

JustKeepSwimming picture JustKeepSwimming · Oct 29, 2014 · Viewed 7.9k times · Source

I am new to WinForms and have a basic form where the user enters data to a TextBox and can press either "save" or "cancel." I wanted to implement data validation to ensure the user actually enters something into the TextBox, but as of now, the ErrorProvider icon only appears if the TextBox, itself, is clicked, and is not checking validation when the "Save" button is pressed like I was intending. I'm also using Visual Studio 2013.

This event handler code is in the btnSave_Click method:

this.txtNote.Validating += new
        System.ComponentModel.CancelEventHandler(this.txtNote_Validating);

And the txtNote_Validating method looks like:

protected void txtNote_Validating(object sender,
                         System.ComponentModel.CancelEventArgs e)
    {
        if(txtNote.Text.Length == 0)
        {
            errorProvider1.SetError((Control)txtNote, "An explanation of your time entry is required.");
        }
        else
        {
            errorProvider1.SetError(txtNote, "");
        }
    }

Also, I have added no events into the properties window for my txtNote, and HAVE added a validating event: txtNote_Validating and Click: btnSave_Click to my btnSave events in the property window.

My question is why does my TextBox only validate when I click on it, and how can I make my "save" button check the validation of the TextBox with the ErrorProvider component?

Answer

Sinatr picture Sinatr · Oct 29, 2014

I think the whole concept of validating is crap. Why would I want to validate TextBox value on loosing focus? I want to validate it as user inputting text or at the end, when user press Ok button to check cross-dependencies of entered values.

Specifically in your case: validation will not occurs because you may click Save button without entering anything into TextBox. Or it will occurs when you click Cancel button, while in the middle of entering value into TextBox, which is stupid, as you just want to close stupid form ;)

There are 2 approaches of validations:

  • instant, during edit, preventing user from accessing invalid commands;
  • final, to gently reject user command.

First one basically monitor user input all time and keep button Save disabled until all fields are filled and values are ok. Second one keep button Save enabled all time, but as soon as user press it, everything will be validated and if something invalid - nothing will happens.

Both approaches can use hints for the user to display what is wrong. In your case ErrorProvider.

Let's apply second approach

void buttonSave_Clicked(object sender, EventArgs e)
{
    if(string.IsNullOfEmpty(txtNote))
    {
        errorProvider1.SetError(txtNote, "Omg, can't haz empty note");
        return;
    }
    if(string.IsNullOfEmpty(someOtherTextBox))
    {
        errorProvider1.SetError(someOtherTextBox, "Omg, no empty plx!");
        return;
    }
    // 
    ...
}

Here we validate values one by one. The first one in the order will cause ErrorProvider to be set and function will exit. It is also possible to show ErrorProvider for all invalid controls:

void buttonSave_Clicked(object sender, EventArgs e)
{
    bool isOk = true;
    if(string.IsNullOfEmpty(txtNote))
    {
        errorProvider1.SetError(txtNote, "Omg, can't haz empty note");
        isOk = false;
    }
    if(string.IsNullOfEmpty(someOtherTextBox))
    {
        errorProvider1.SetError(someOtherTextBox, "Omg, no empty plx!");
        isOk = false;
    }
    // 
    if(isOk)
    {
        ...
    }
}

One problem is what ErrorProvider, once set, will continue blinking forever (or until you fix mistake and click button again). Simple workaround is to use Timer which will turn off error after few seconds. Once you set error - start timer, when time expires:

private void timerError_Tick(object sender, EventArgs e)
{
    timerError.Stop();
    errorProvider1.Clear();
}