以编程方式检查控件时如何防止触发 CheckedChanged 事件?

Posted

技术标签:

【中文标题】以编程方式检查控件时如何防止触发 CheckedChanged 事件?【英文标题】:How to prevent firing CheckedChanged event when checking a control programmatically? 【发布时间】:2011-12-26 16:57:55 【问题描述】:

我通常这样做。

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

有没有更好或更通用的解决方案?

【问题讨论】:

这是正确的方法。从技术上讲,您应该在 finally 块中将 isFrozen 设置回 false。 【参考方案1】:

我认为你的方式很好。

另一种方法是在检查之前删除 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

【讨论】:

好主意。我从未想过要删除这些事件。 这应该被标记为正确答案。即使此功能与 OP 的方法没有明显差异,这表达意图也是一种非常清晰的方式,因此处理此代码的下一个人可以清楚地理解正在做什么以及为什么,即使没有 cmets 来解释它。 当你不知道绑定到信号的插槽是什么的时候呢?那是假设只有一个。我更喜欢事件的“交换”方法。 var e = new typeof(btn.Changed); e.Swap(btn.Changed); btn.Checked = false; e.Swap(btn.Changed); @v.oddou 这个var e = new typeof(btn.Changed); 的来源不是很清楚。 btn.Changed? e.Swap? @LarsTech 你不能在 C# 中做到这一点,我提出了事件不是一等公民的问题。我认为这很糟糕。它们应该是可分配的、可构造的和可交换的,就像升压信号一样。 new typeof(btn.Changed) 只是一种虚构的方式来创建一个空事件,当临时分配给 btn.Changed 时不会导致附加的插槽触发。【参考方案2】:

在 VB 中:

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

【讨论】:

答案是关于 C# 而不是 VB。 但是对于我们中的一些想如何用 C#(我们的第一语言)执行此操作,但不得不在 VB.net(客户的请求)中编写代码的人来说,它很有用。 虽然我非常感谢这个答案,但我认为它应该作为评论添加到已接受的答案中。【参考方案3】:

我想实现这样的事情一段时间后发现了这篇文章。我经常使用 National Instruments 的 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;
    

我确信需要改进,但我的初步测试表明它有效。我在此处发布只是为了以防其他人偶然发现此问题并希望以更清晰的方式区分更改的发起位置。欢迎任何 cmets。

【讨论】:

感谢您提出此尼克。当我遇到这个时,我正试图记住如何在 Measurement Studio 中执行此操作。【参考方案4】:

只需设置一个计数器值并检查事件开始时的值。它在 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;
        

【讨论】:

以上是关于以编程方式检查控件时如何防止触发 CheckedChanged 事件?的主要内容,如果未能解决你的问题,请参考以下文章

如何以编程方式根据排序标准对单元格重新排序 SWIFT 4

如何防止指定任务触发

单击按钮时如何以编程方式触发刷新primeNG数据表

IOS如何防止下载的图片以编程方式缓存

如何以编程方式防止 Windows 硬盘驱动器减速?

当我以编程方式更改用户控件时,如何让数据绑定双向工作?