Windows Develop Bookmark and Share   
 index > Windows Forms Data Controls and Databinding > Binding.Parse occurring before Validating
 

Binding.Parse occurring before Validating

From what I gather from MSDN docs, and books like Data Binding with Windows Forms 2.0 (Brian Noyes, pg163), the correct order of events are:
Validating, Parse, Validated when you change a bound TextBox for example. But what I am observing is that Parse happens first, so it updates the data source, and Validating event happens at the very last of the event sequences. Setting Cancel to true there, well, isn't doing much in this process then.

Below is a sample that demonstrates this behavior.

public partial class Form1 : Form
{
    private Foo _foo;

    public Form1()
    {
        InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
        button1.Enabled = false;
        _foo = new Foo();
        BindingSource bs = new BindingSource(components);
        bs.DataSource = _foo;

        textBox1.DataBindings.Add("Text", bs, "Name", true, DataSourceUpdateMode.OnValidation);
        textBox1.Validating += new CancelEventHandler(textBox1_Validating);
        textBox1.Leave += new EventHandler(textBox1_Leave);
        textBox1.DataBindings["Text"].Format += new ConvertEventHandler(textBox1_Format);
        textBox1.DataBindings["Text"].Parse += new ConvertEventHandler(textBox1_Parse);
    }

    void textBox1_Leave(object sender, EventArgs e)
    {
        System.Diagnostics.Debug.Print("Leave textBox1");
    }

    void textBox1_Parse(object sender, ConvertEventArgs e)
    {
        System.Diagnostics.Debug.Print("Parse textBox1");
    }

    void textBox1_Format(object sender, ConvertEventArgs e)
    {
        System.Diagnostics.Debug.Print("Format textBox1");
    }

    void textBox1_Validating(object sender, CancelEventArgs e)
    {
        System.Diagnostics.Debug.Print("Validating textBox1");
    }

    private void button3_Click(object sender, EventArgs e)
    {
        System.Diagnostics.Debug.Print("textBox1.Text = {0}", textBox1.Text);
        System.Diagnostics.Debug.Print("Foo.Name = {0}", _foo.Name);
    }
}

public class Foo : IDataErrorInfo
{
    private string _error;
    private Dictionary<string, string> _errors;
    private string _name;

    public Foo()
    {
        _error = String.Empty;
        _errors = new Dictionary<string, string>();
        _errors["Name"] = String.Empty;
    }

    public string[] AvailableNames
    {
        get
        {
            if (_availableNames == null)
            {
                _availableNames = new string[] {
                    "John", "Jeff", "Elton", "Bar", "Robert" };
            }
            return _availableNames;
        }
    }
    private string[] _availableNames;

    public string Name
    {
        get { return _name; }
        set
        {
            _name = value;
            if (!String.IsNullOrEmpty(_name) && !String.Equals(_name, "Bar", StringComparison.CurrentCultureIgnoreCase))
                _errors["Name"] = "That name isn't right.";
            else
                _errors["Name"] = String.Empty;
            if (NameChanged != null)
                NameChanged(this, EventArgs.Empty);
        }
    }

    public event EventHandler NameChanged;

    #region IDataErrorInfo Members

    public string Error
    {
        get { return _error; }
    }

    public string this[string columnName]
    {
        get { return _errors[columnName]; }
    }

    #endregion
}
doughboy  Wednesday, May 06, 2009 8:01 PM
Hi doughboy,

Actually, if you debug into the Framework Source Code, you can see Control.OnValidating method is called first after you click button3. Control.OnValidating method will call Binding.Target_Validate method which calls Binding.OnParse method. At last OnValidating method will fire validating event. This is why you see the parse event is fired before Control.Validating event.

So it is not accurate to determine to event fired sequence based on the output of the above code.


Best regards,
Bruce Zhou
Please mark the replies as answers if they help and unmark if they don't.
Bruce.Zhou  Friday, May 08, 2009 5:36 AM
Thanks for that. I found out the same looking through Reflector as well yesterday.
However, it doesn't really resolve my issue of event sequences.

The main issue is that even though OnValidating may be called first. Validating does not get called until after the change has been persisted.
So the handler for Validating really has no way to veto the change. It happens after the fact.
That is what's confusing about this whole thing.
doughboy  Friday, May 08, 2009 2:05 PM

>>So the handler for Validating really has no way to veto the change. It happens after the fact.
That is what's confusing about this whole thing.<<

Well, to "veto the change", you simply set the e.Cancel = true ... that's the whole point of the Validating event. Then the user can't leave the TextBox until it's fixed.

Personally, I don't typically like forcing this upon the user this way, but there are many ways to skin a cat. What exactly are you trying to accomplish? Maybe there's a better way to do this ....


~~Bonnie Berent [C# MVP]
BonnieB  Saturday, May 09, 2009 5:21 PM
Hi doughboy,

BonnieB is right. The validating code in the validating event handler still has the chance to deny the change. You can set e.Cancel to true to prevent the focus from moving to other controls.

If you are still confused, please feel free to let us know.


Best regards,
Bruce Zhou
Please mark the replies as answers if they help and unmark if they don't.
Bruce.Zhou  Tuesday, May 12, 2009 3:00 AM

Bonnie,

Are you suggesting that I set e.Cancel in the handler of Validating event? textBox1_Validating, for example, from my code?

Even though that may keep the UI in place for the user to fix the value, that is after the fact that the new value has been written to the underlying datasource.

Parse gets called first, which writes the change to the underlying datasource, then eventually Validating even is raised, by which time, it's too late. Now we have to reverse the change somehow. I'd have thought that Validating occur first so that if the validation fails, the underlying datasource is never touched. But that's not the case.

doughboy  Thursday, August 20, 2009 3:00 PM
This is all I see in Reflector:


[EditorBrowsable(EditorBrowsableState.Advanced)]
protected virtual void OnValidating(CancelEventArgs e)
{
    CancelEventHandler handler = (CancelEventHandler) base.Events[EventValidating];
    if (handler != null)
    {
        handler(this, e);
    }
}


Are you saying that Binding subscribes to Validaing event and fires Parse? then Validating?, etc.
Then I get you. But still this seems backwards to me. Binding basically commits the change to the datasource, then raises Validating event? What good is canceling (via e.Cancel = true) if the change was already committed?
doughboy  Thursday, August 20, 2009 3:06 PM
It does seem a bit backwards to me, but yes, the Parse event does fire before the Validating. However, if you have set e.Cancel to true, then there's absolutelyno way for the userto exit from the control, so it's a moot point that the value got written to the data, because the user will have to change it before anything further can happen, thus when all is said and done, a valid value will have to be entered into that control anyway.

Again, this is not, in my opinion, a desirable user-experience, but many softwareprograms operate this way. Personally, I prefer to have a visual indication to the user that the field contains invalid data so that they can fix it at their leisure (we give our controls a red background color to indicate this).
~~Bonnie Berent [C# MVP]
BonnieB  Sunday, August 23, 2009 4:26 AM

You can use google to search for other answers

Custom Search

More Threads

• Help with an editable PK and a datagridview (sql server 2005 + C#)
• need help with datagridview
• Preserve offset of vertical scrollbar
• DataGridView
• Tableadapter update problem with transaction
• Validate DataGridView Cells.
• update code works for modify but not add new
• DataBindings TabIndex DataTable Modified Problem
• datagrid
• DataGridView custom DataGridViewButtonColumn text