Why isn't the binding value saved in the data source on first change when using EndCurrentEdit?

I have CheckBox

one that has a property Checked

associated with a bool value. During an event CheckedChanged

, several logical loops are executed that use the bool property in the data source.

My problem is the first time the user checks CheckBox

out the associated data source is not updated. Subsequent updates work fine though.

Here is some sample code to test the problem. Just create an empty shape and add to it CheckBox

.

public partial class Form1 : Form
{
    private bool _testBool;
    public bool TestBool
    {
        get { return _testBool; }
        set { _testBool = value; }
    }

    public Form1()
    {
        InitializeComponent();

        checkBox1.DataBindings.Add(new Binding("Checked", this, "TestBool"));
        checkBox1.CheckedChanged += new EventHandler(checkBox1_CheckedChanged);
    }

    void checkBox1_CheckedChanged(object sender, EventArgs e)
    {
        checkBox1.BindingContext[this].EndCurrentEdit();

        Debug.WriteLine(TestBool.ToString());
    }
}

      

The first time I check the checkbox, the property TestBool

stays at false even if it is checkBox1.Checked

set to true

. Subsequent changes update the property correctly TestBool

to match checkBox1.Checked

.

If I add a breakpoint to the event CheckedChanged

and swipe checkBox1.BindingContext[this].Bindings[0]

out of the immediate window, I can see that modified = false

on first run, which is probably why the EndCurrentEdit()

datasource is not updating correctly.

The same thing happens when using the event TextBox

and TextChanged

, therefore, it is not limited to only CheckBox.Checked

.

Why is this? And is there a general general way of solving the problem?

Edit: I know of a few workarounds so far, although none are perfect as they are not universal and need to be remembered every time we want to use an event Changed

.

  • setting a property in the data source directly from the CheckedChanged event
  • binding search and invocation WriteValue()

  • connecting bindings after loading the control

I'm more worried about why this is happening, although if anyone knows of a standard generic solution to prevent it from relying on any special encoding in the event Changed

, I'd be happy with that too.

+3


source to share


3 answers


Controls usually want to pass validation before writing to the data source, so writing a value usually won't happen until you try to leave the control.

You can force the value to be written:



void checkBox1_CheckedChanged(object sender, EventArgs e) {
  Binding b = checkBox1.DataBindings["Checked"];
  if (b != null) {
    b.WriteValue();
  }
  Debug.WriteLine(TestBool.ToString());
}

      

+1


source


The event appears to be CheckedChanged

too early in the process.

But you can use BindingComplete

:

public partial class Form1 : Form
{
    private Boolean _testBool;
    public Boolean TestBool
    {
        get { return _testBool; }
        set { _testBool = value; }
    }

    public Form1()
    {
        InitializeComponent();

        checkBox1.DataBindings.Add(new Binding("Checked", this, "TestBool", true, DataSourceUpdateMode.OnPropertyChanged));
        checkBox1.DataBindings[0].BindingComplete += Form1_BindingComplete;
    }

    private void Form1_BindingComplete(Object sender, BindingCompleteEventArgs e)
    {
        Debug.WriteLine("BindingComplete:  " + TestBool.ToString());
    }
}

      



Note that the event is triggered on startup when the original binding occurs. You have to deal with the potential unintended consequences, but otherwise it works the first time you click and every click.

Also note that true

(format) is required in the constructor Binding

to make the event fire.

0


source


The closest I can find to explain this behavior is this third party explanation

Basically, this is a problem of timing. The way the binding works in DotNet is actually very simple. There is no magic in the DotNet framework that tells the BindingManager when something changes. What does it do when you bind to a property (like CheckedValue). The BindingManager looks for an event on a control called propertynameChanged (for example, "CheckedValueChanged"). This is the same event when your code connects to your sample form.

When a control fires an event, the order in which listeners receive the event is arbitrary. There is no reliable way to tell whether the BindingManager will receive the event first or by the Form.

The My event CheckBox1_CheckChanged

runs before it BindingManager

handles the changed event, so the data source was not updated at this time.

My best guess is why this is only happening the first time that the control is not showing yet, so some code doesn't run to fix the order events in which it handles. I have seen other posts about not being able to bind to invisible elements due to the handle not being created yet, and one answer states

Until the control is first visible, some initialization in the background will never happen, and part of that initialization is allowing data binding.

So I suspect it has something to do with it.

I can verify that if I attach a Changed handler later, for example during an event Load

, it works as I expected.

public partial class Form1 : Form
{
    private bool _testBool;
    public bool TestBool
    {
        get { return _testBool; }
        set { _testBool = value; }
    }

    public Form1()
    {
        InitializeComponent();

        checkBox1.DataBindings.Add(new Binding("Checked", this, "TestBool"));
        Load += new EventHandler(Form1_Load);
    }

    void Form1_Load(object sender, EventArgs e)
    {
        checkBox1.CheckedChanged += new EventHandler(checkBox1_CheckedChanged);
    }

    void checkBox1_CheckedChanged(object sender, EventArgs e)
    {
        // Not needed anymore
        //checkBox1.BindingContext[this].EndCurrentEdit();

        Debug.WriteLine(TestBool.ToString());
    }
}

      

0


source







All Articles