如何在程序控制下检查控件时防止触发CheckedChanged事件?

36

如何在编程时防止触发CheckedChanged事件?

通常我会这样做。

private bool isFrozen = false;

private void btn1_CheckedChanged(object sender, EventArgs e)
{
    if (isFrozen) 
        return;

    isFrozen = true;
    btn2.Checked = false;
    isFrozen = false;

    // Do some stuff
}

private void btn2_CheckedChanged(object sender, EventArgs e)
{
    if (isFrozen) 
        return;

    isFrozen = true;
    btn1.Checked = false;
    isFrozen = false;

    // Do another stuff
}

有更好或更常见的解决方案吗?


1
这是正确的方式。从技术上讲,你应该在 finally 块中将 isFrozen 设置回 false。 - Hans Passant
4个回答

62

我认为你的方法是可以的。

另一种方法是在检查之前移除EventHandler,然后在检查之后再添加回来。这种方式可以消除isFrozen变量的需要。

private void btn1_CheckedChanged(object sender, EventArgs e)
{
  btn2.CheckedChanged -= btn2_CheckedChanged;
  btn2.Checked = false;
  btn2.CheckedChanged += btn2_CheckedChanged;

    // Do some staff
}

private void btn2_CheckedChanged(object sender, EventArgs e)
{
  btn1.CheckedChanged -= btn1_CheckedChanged;
  btn1.Checked = false;
  btn1.CheckedChanged += btn1_CheckedChanged;

    // Do another staff
}

3
这应该标记为正确答案。即使在这种方式与原帖的方法之间没有明显差异的情况下,它也以非常清晰的方式表达了意图,因此下一个处理此代码的人即使没有注释说明也能清楚地理解正在做什么以及为什么要这样做。 - Jim
您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - v.oddou
@v.oddou 不是很清楚 var e = new typeof(btn.Changed); 是从哪里来的。btn.Changede.Swap - LarsTech
@LarsTech,你不能在C#中这样做。我提出了一个问题,即事件不是一等公民。在我看来,这很糟糕。它们应该像boost信号那样可分配、可构建和可交换。new typeof(btn.Changed)只是一种想象中的创建空事件的方式,当暂时分配给btn.Changed时,不会导致附加的插槽触发。 - v.oddou
@v.oddou -= 和 += 只有在事件是属性时才允许使用。如果它是字段,你可以做更多的操作。 - Logman
显示剩余2条评论

8

在VB中:

RemoveHandler btn2.CheckedChanged, AddressOf btn2_CheckedChanged
btn2.Checked = false
AddHandler btn2.CheckedChanged, AddressOf btn2_CheckedChanged

4
答案是关于C#而不是VB。 - Daniel Fath
8
但对于我们中的一些人来说,这是有用的,因为我们曾考虑用C#(我们的第一语言)来完成这个任务,但不得不使用VB.net编写代码(客户的要求)。 - Laki Politis
1
虽然我非常感谢这个答案,但我认为它应该作为对被接受的答案的评论添加。 - Eric

6

我想实现类似的功能已经有一段时间了,后来看到了这篇文章。我经常使用国家仪器的Measurement Studio和他们的WinForms控件,其中具有事件StateChanging或StateChanged的控件会传递一个ActionEventArgs类型的参数,该参数具有一个Action属性,可以取三个值:ByKeyboard、ByMouse和Programatic。这对于确定控件状态更改的原因非常有用。我想在标准WinForms复选框中复制此功能。

以下是我的代码:

public enum ControlSource
{
    Programatic,
    ByKeyboard,
    ByMouse
}

public class AwareCheckBox : Checkbox
{
    public AwareCheckBox()
            : base()
    {
        this.MouseDown += AwareCheckbox_MouseDown;
        this.KeyDown += AwareCheckbox_KeyDown;
    }

    private ControlSource controlSource = ControlSource.Programatic;

    void AwareCheckbox_KeyDown(object sender, KeyEventArgs e)
    {
        controlSource = ControlSource.ByKeyboard;
    }

    void AwareCheckbox_MouseDown(object sender, MouseEventArgs e)
    {
        controlSource = ControlSource.ByMouse;
    }

    public new event AwareControlEventHandler CheckedChanged;
    protected override void OnCheckedChanged(EventArgs e)
    {
        var handler = CheckedChanged;
        if (handler != null)
            handler(this, new AwareControlEventArgs(controlSource));

        controlSource = ControlSource.Programatic;
    }
}

public delegate void AwareControlEventHandler(object source, AwareControlEventArgs e);

public class AwareControlEventArgs : EventArgs
{
    public ControlSource Source { get; private set; }

    public AwareControlEventArgs(ControlSource s)
    {
        Source = s;
    }
}

我相信还有改进的空间,但是我的初步测试已经证明它可以工作。我在这里发布只是为了让其他人在遇到这个问题时更清楚地区分变化的起源。欢迎任何评论。


1
谢谢你发布这个,Nick。我在尝试回忆如何在Measurement Studio中完成它时发现了这个。 - Grant Johnson

0

只需设置一个计数器值并在事件开始时检查该值即可。这在10分钟内解决了我的问题。我正在使用Xamarin中的5个滑动按钮将其制作成单选按钮。

 private void testtoggle1(object sender, ToggledEventArgs e)
        {
            if (chk_ctr == 1) { return; }
            chk_ctr = 1;
            sw2.IsToggled= false;
            sw3.IsToggled = false;
            sw4.IsToggled = false;
            sw5.IsToggled = false;
            chk_ctr = 0;
        }
        private void testtoggle2(object sender, ToggledEventArgs e)
        {
            if (chk_ctr == 1) { return; }
            chk_ctr = 1;
            sw1.IsToggled = false;
            sw3.IsToggled = false;
            sw4.IsToggled = false;
            sw5.IsToggled = false;
            chk_ctr = 0;

        }
        private void testtoggle3(object sender, ToggledEventArgs e)
        {
            if (chk_ctr == 1) { return; }
            chk_ctr = 1;
            sw1.IsToggled = false;
            sw2.IsToggled = false;
            sw4.IsToggled = false;
            sw5.IsToggled = false;
            chk_ctr = 0;
        }
        private void testtoggle4(object sender, ToggledEventArgs e)
        {
            if (chk_ctr == 1) { return; }
            chk_ctr = 1;
            sw1.IsToggled = false;
            sw2.IsToggled = false;
            sw3.IsToggled = false;
            sw5.IsToggled = false;
            chk_ctr = 0;
        }
        private void testtoggle5(object sender, ToggledEventArgs e)
        {
            if (chk_ctr == 1) { return; }
            chk_ctr = 1;
            sw1.IsToggled = false;
            sw2.IsToggled = false;
            sw3.IsToggled = false;
            sw4.IsToggled = false;
            chk_ctr = 0;
        }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接