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

我有一个带有复选框的树视图,我有“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(); } } } 

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

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

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

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

并将其余代码放在GetAvailableFiles() 。 这在事件代码和动作代码之间产生了分离,大多数人都认为这是值得区分的。

其次,在您的情况下可能适用或不适用的是多个事件可能导致相同的操作。 比如mnuFileQuit_ClickmnuFileQuit_Click作为一个明显的例子。 如果两者都调用CloseApplication()它会删除大量冗余代码。

使用: if(e.Action != TreeViewAction.Unknown)而不是if (!_isCheckingInProgress) 。 请参见TreeViewAction

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

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

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

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

就个人而言,我使用一个删除然后添加事件的函数。

 private void trvAvailableFiles_AfterCheck(object sender, TreeViewEventArgs e) { EnableEvents(false); 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(); SetChildrenCheckState(e.Node, isChecked); } finally { trvAvailableFiles.EndUpdate(); } EnableEvents(true); } private void EnableEvents(bool bEnable) { if(bEnable) cbWhatever.OnChecked += EventHandler; else cbWhatever.OnChecked -= EventHandler; } 

不,没有更清洁的方法来做你所展示的。 我不确定为什么你觉得变量是一种“黑客”方法。 设置标志是编写UI代码时常用的技术。

真正的黑客将是一些不明确的方式来防止一次提升事件,但不是随后的时间。 未来的维护程序员可以保证了解设置标志的工作原理; 他们无法保证欣赏您的替代方法的“优雅”。