Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I ignore simple events firing when changing control states in C# Windows Forms?

I'm creating a simple form in C# Windows Forms and run into a common situation where one control can alter the state of another, but both controls' events trigger some other method.

For example, consider a Checkbox and NumericUpDown where the state or value of either one should trigger something to redraw. The NumericUpDown is dependent upon the Checkbox meaning it could be disabled or ignored unless the Checkbox is checked.

However, it is convenient for the user to change the NumericUpDown value, and have the Checkbox be automatically checked if it wasn't already.

So here are the methods in question:

private void chkState_CheckedChanged(object sender, EventArgs e)
{
    RedrawStuff();
}

private void numStateValue_ValueChanged(object sender, EventArgs e)
{
    if (!chkState.Checked)
        chkState.Checked = true;
    RedrawStuff();
}

The problem of course, is that changing the NumericUpDown value causes RedrawStuff() to fire twice.

My workaround is to introduce a boolean where I effectively can negate this behavior, but sometimes it can get messy:

bool _preventStateChange;

private void chkState_CheckedChanged(object sender, EventArgs e)
{
    if (_preventStateChange)
        return;
    RedrawStuff();
}

private void numStateValue_ValueChanged(object sender, EventArgs e)
{
    _preventStateChange = true;
    if (!chkState.Checked)
        chkState.Checked = true;
    RedrawStuff();
    _preventStateChange = false;
}

Is this the best way to handle this situation?

like image 645
JYelton Avatar asked Jul 07 '11 00:07

JYelton


2 Answers

For the more general case, if you have complex relations between the controls, you could check which control fired the event by checking its own Focused property:

private void chkState_CheckedChanged(object sender, EventArgs e)
{
    if (chkState.Focused)
        RedrawStuff();
}

private void numStateValue_ValueChanged(object sender, EventArgs e)
{
    if (!chkState.Checked)
        chkState.Checked = true;

    if (numStateValue.Focused)
        RedrawStuff();
}

This way, each object is only dependent on itself.

As far as I know, the object must have focus to fire a user event, and there can only be one object with focus at any given time. However, I'm not sure it will work in all cases so this still needs testing.

like image 167
Yanir Kleiman Avatar answered Nov 14 '22 22:11

Yanir Kleiman


Just move RedrawStuff(); to an else clause. This way it's called in both situations, but only once.

private void chkState_CheckedChanged(object sender, EventArgs e)
{
    RedrawStuff();
}

private void numStateValue_ValueChanged(object sender, EventArgs e)
{
    if (!chkState.Checked)
        chkState.Checked = true;
    else
        RedrawStuff();
}
like image 44
Nahydrin Avatar answered Nov 14 '22 22:11

Nahydrin