在C#Windows窗体中更改控件状态时,如何忽略触发的简单事件?

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

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

对于更一般的情况,如果控件之间有复杂的关系,您可以通过检查自己的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(); } 

这样,每个对象仅依赖于自身。

据我所知,该对象必须具有激发用户事件的焦点,并且在任何给定时间只能有一个具有焦点的对象。 但是,我不确定它是否适用于所有情况,因此仍需要测试。

只需移动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(); } 

我认为如果控件被禁用, CheckBox上的CheckedChanged不会触发,所以这样做:

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

如果我记错了,就投票了。

您可以在“RedrawStuff”方法的开头“取消连接”更改事件,并在最后再次连接它们。


private void RedrawStuff()
{
//取消更改事件的连线
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);

}

(我已经使用过这种方法几次,因为它似乎可以解决你所描述的问题,但如果有人要指出为什么,由于我可能不理解的原因,我会很高兴它可能是一个糟糕的方法。)