我在C#Windows窗体中创建一个简单的表单并遇到一种常见情况,一个控件可以改变另一个控件的状态,但两个控件的事件都会触发其他一些方法。
例如,考虑Checkbox
和NumericUpDown
,其中任何一个的状态或值都应触发重绘的内容。 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;
}
触发两次。
我的解决方法是引入一个布尔值,我可以有效地否定这种行为,但有时它会变得混乱:
{{1}}
这是处理这种情况的最佳方式吗?
答案 0 :(得分:6)
对于更一般的情况,如果控件之间有复杂的关系,您可以通过检查自己的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();
}
这样,每个对象只依赖于自身。
据我所知,该对象必须具有触发用户事件的焦点,并且在任何给定时间只能有一个具有焦点的对象。但是,我不确定它是否适用于所有情况,因此仍需要测试。
答案 1 :(得分:1)
将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();
}
答案 2 :(得分:1)
您可以在“RedrawStuff”方法的开头“取消连接”更改事件,并在最后再次连接它们。
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);
}
(我已经使用过这种方法几次,因为它似乎可以解决你所描述的问题,但如果有人要指出为什么我可能不理解的原因,我会很高兴这可能是一个糟糕的方法。)
答案 3 :(得分:1)
如果控件被禁用,我认为CheckedChanged
上的CheckBox
不会触发,所以这样做:
private void numStateValue_ValueChanged(object sender, EventArgs e)
{
if (!chkState.Checked)
{
chkState.Enabled = false;
chkState.Checked = true;
chkState.Enabled = true;
}
RedrawStuff();
}
如果我记错了,就要投票了。