winforms 在C# Windows Form中变更控件状态时,如何忽略引发的简单事件?

h7appiyu  于 2022-11-17  发布在  C#
关注(0)|答案(4)|浏览(210)

我正在C# Windows窗体中创建一个简单的窗体,遇到了一种常见的情况,即一个控件可以更改另一个控件的状态,但两个控件的事件都触发了某个其他方法。
例如,考虑CheckboxNumericUpDown,其中任何一个的状态或值都应该触发重绘。NumericUpDown依赖于Checkbox,这意味着它可以被禁用或忽略,除非选中Checkbox
但是,用户可以方便地更改NumericUpDown值,并自动检查Checkbox(如果尚未检查)。
下面是一些有问题的方法:

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

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

当然,问题是更改NumericUpDown值会导致RedrawStuff()触发两次。
我的解决方法是引入一个布尔值,在这里我可以有效地否定这种行为,但有时候会变得很混乱:

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;
}

这是处理这种情况的最好方法吗?

dxxyhpgq

dxxyhpgq1#

对于更一般的情况,如果控件之间有复杂的关系,则可以通过检查其自身的Focused属性来检查哪个控件触发了事件:

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();
}

这样,每个对象都只依赖于它自己。
据我所知,对象必须有焦点才能触发用户事件,并且在任何给定时间只能有一个对象有焦点。但是,我不确定它是否在所有情况下都能工作,所以这仍然需要测试。

js4nwp54

js4nwp542#

只需将RedrawStuff();移到else子句中,这样它在两种情况下都会被调用,但只调用一次。

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();
}
vs91vp4v

vs91vp4v3#

您可以在“RedrawStuff”方法开始时“取消连接”change事件,并在结束时再次连接它们。

private void RedrawStuff()
{
    // un-wire the change events
    chkState.CheckedChanged -= new System.EventHandler(chkState_CheckedChanged);
    numStateValue.ValueChanged -= new System.EventHandler(chkState_CheckedChanged);

    /*
  .... do you thing...including setting the state of both / either controls
       based on the state of things, without fear of triggering recursive changes...
*/

// wire them back up
chkState.CheckedChanged += new System.EventHandler(chkState_CheckedChanged);
numStateValue.ValueChanged += new System.EventHandler(chkState_CheckedChanged);

}
(我已经用过几次这种方法,因为它似乎能解决你所描述的问题,但如果有人能指出为什么,我可能不明白,它可能是一个坏的方法,我会很高兴。)

envsm3lx

envsm3lx4#

我认为如果控件被禁用,CheckBox上的CheckedChanged不会触发,因此执行以下操作:

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

相关问题