C# 如何判断事件是否来自C中的用户输入?

C# 如何判断事件是否来自C中的用户输入?,c#,winforms,checkbox,event-handling,C#,Winforms,Checkbox,Event Handling,我有一个小表单,上面有一些复选框,CheckChanged事件的每个复选框都有一个消息处理程序。由于某些复选框依赖于其他复选框,因此如果一个复选框的选中状态发生更改,则会更改任何相关复选框的选中状态。我发现这会导致在其他复选框上引发事件,但我的问题是,每个事件都有一个函数调用,只有当事件来自用户实际单击复选框时,才应该调用该函数调用。我想知道,如果CheckChanged事件是由鼠标单击引起的,那么应该如何从发送者或EventArgs中判断 悬崖: 接收CheckChanged事件的多个复选框

我有一个小表单,上面有一些复选框,CheckChanged事件的每个复选框都有一个消息处理程序。由于某些复选框依赖于其他复选框,因此如果一个复选框的选中状态发生更改,则会更改任何相关复选框的选中状态。我发现这会导致在其他复选框上引发事件,但我的问题是,每个事件都有一个函数调用,只有当事件来自用户实际单击复选框时,才应该调用该函数调用。我想知道,如果CheckChanged事件是由鼠标单击引起的,那么应该如何从发送者或EventArgs中判断

悬崖:

接收CheckChanged事件的多个复选框 需要确定事件是否由鼠标单击引发
您可以使用标志指示是否忽略事件。这可能比取消订阅事件处理程序更容易。这不是很复杂,但它应该可以完成这项工作

我举了一个简单的例子:

   bool ignoreEvents = false;
        public Form1()
        {
            InitializeComponent();
        }

        private void checkBox1_CheckedChanged(object sender, EventArgs e)
        {
            ignoreEvents = true;
            checkBox2.Checked = checkBox1.Checked ;
            checkBox3.Checked = checkBox1.Checked;
            ignoreEvents = false;
        }

        private void checkBox2_CheckedChanged(object sender, EventArgs e)
        {
            if (ignoreEvents) return;
            MessageBox.Show("Changed in 2");
        }

        private void checkBox3_CheckedChanged(object sender, EventArgs e)
        {
            if (ignoreEvents) return;
            MessageBox.Show("Changed in 3");
        }

为了获得更高的代码稳定性,还可以使用类TriggerLock而不是ignoreEvents标志

    private void checkBox1_CheckedChanged(object sender, EventArgs e)
    {
        using (new TriggerLock())
        {
            checkBox2.Checked = checkBox1.Checked;
            checkBox3.Checked = checkBox1.Checked;
        }
    }

    private void checkBox2_CheckedChanged(object sender, EventArgs e)
    {
        if (TriggerLock.IsOpened)
        {
            MessageBox.Show("Changed in 2");
        }
    }

    private void checkBox3_CheckedChanged(object sender, EventArgs e)
    {
        if (TriggerLock.IsOpened)
        {
            MessageBox.Show("Changed in 3");
        }
    }
TriggerLock类的工作原理与信号灯类似:

public class TriggerLock
    : IDisposable
{
    private static int _nUsing = 0;
    private bool _bDisposed;

    public TriggerLock()
    {
        _bDisposed = false;
        Interlocked.Increment(ref _nUsing);
    }
    ~TriggerLock()
    {
        Dispose(false);
    }

    public static bool IsOpened 
    {
        get { return _nUsing == 0; }
    }

    public void Dispose()
    {
        Dispose(true);
    }
    private void Dispose(bool bDisposing)
    {
        if (bDisposing && !_bDisposed)
        {
            Interlocked.Decrement(ref _nUsing);
            _bDisposed = true;
        }
    }
}

当他们使用tab键和空格键进行导航和选择时会怎么样?在尝试破坏输入法之前,我会先整理一下你的逻辑。我可能会断开事件处理程序的连接,然后重新连接它们。你能告诉我们为什么你想知道他们选择使用的是鼠标吗?它可能会帮助我们。在我能想到的几乎所有情况下,这都不会有任何区别…@Penfold这是一个如此详细的问题,实际上非常清楚-因为,副作用的逻辑。谢谢你的快速回复@Grant,同样的规则也适用于键盘按键我希望事件被触发,因此问题可以被改写为如何判断事件是否是由用户输入引起的,而不是程序的副作用。这就成功了,实现起来非常简单,谢谢!编辑:我有点失望,虽然没有一个回复可以从事件句柄的参数中挑出信息,但是您的类如何区分直接用户交互(例如用户单击复选框)引发的事件和副作用逻辑(例如用户单击复选框)引发的事件,哪个会导致其他复选框更改状态?该类不会隐式区分用户交互和副作用。这只是Alex想法的一个改进的防异常版本。我认为使用静态变量是一个非常糟糕的想法。如果这个类用于同一个项目的两个不相关的部分呢?这将导致混乱的结束。最好使用一个实例字段,让用户在字段中保留这个类的名称和对象。这是GUI中最常见的情况。该类允许嵌套锁定,并且是异常安全的。如果您必须同时在多个对话框中锁定事件,或者在GUI中使用多线程,则应更改模式。我使用VB6中已有的模式;