如何防止事件导致自己的事件在C#中触发?

Viq*_*ish 5 .net c# treeview events winforms

我有一个带有复选框的树视图,我有"AfterCheck"事件的以下处理程序:

private void trvAvailableFiles_AfterCheck(object sender, TreeViewEventArgs e)
{
    if (!_isCheckingInProgress)
    {
        trvAvailableFiles.BeginUpdate();

        var nodePath = e.Node.Tag.ToString();
        bool isChecked = e.Node.Checked;
        e.Node.Nodes.Clear();

        try
        {
            _fileTreeLogic.GetChildNodes(e.Node, true);
            e.Node.ExpandAll();

            _isCheckingInProgress = true;
            SetChildrenCheckState(e.Node, isChecked);
            _isCheckingInProgress = false;

        }
        finally
        {
            trvAvailableFiles.EndUpdate();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

如果仔细观察,你会发现我正在检查"_isCheckingInProgress".如果不是,那么我继续并展开所有节点并调用SetChildrenCheckState()方法.我遇到的问题是SetChildrenCheckState()随后将导致每个子节点都为其自己的节点触发AfterCheck事件.

我的问题是,是否有更简洁的方法允许第一个AfterCheck事件发生而不是后续事件?我必须有一个实例bool变量来检查和设置似乎有点hackish.

Bri*_*ian 6

使用:if(e.Action != TreeViewAction.Unknown)代替if (!_isCheckingInProgress).见TreeViewAction.

当用户使用键盘或鼠标检查复选框时,e.Action将是TreeViewAction.ByKeyboardTreeViewAction.ByMouse.

MSDN将此作为TreeView.AfterCheck事件的示例代码提供.

编辑1:显然,如果您在代码中自己设置复选框,请将事件处理程序中的代码移动到新函数,并使用设置复选框的代码直接调用它.此解决方案的目的是让您使用事件处理程序进行用户输入,而无需在通过代码自行设置复选框时触发这些事件.

编辑2:请参阅斯宾塞的答案,以解释我在编辑1中的评论


Spe*_*ort 4

您偶尔会看到的一项建议是不要将大量代码放入事件处理程序本身。有许多的原因。首先,在您的情况下,理解这样的调用会更容易:

private void trvAvailableFiles_AfterCheck(object sender, TreeViewEventArgs e)
{
    if (!_isCheckingInProgress) 
    {
        _isCheckingInProgress = true;
        try { GetAvailableFiles(); } catch {}
        _isCheckingInProgress = false;
    }
}
Run Code Online (Sandbox Code Playgroud)

并将其余代码放入GetAvailableFiles(). 这在事件代码和操作代码之间创建了分离,大多数人都认为这是值得做出的区分。

其次,这可能适用也可能不适用于您的情况,即多个事件可能会导致相同的操作。作为mnuFileQuit_Click一个btnClose_Click明显的例子。如果两者都调用CloseApplication()它,就会删除很多冗余代码。