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

时间:2011-02-16 05:10:13

标签: c# .net winforms events treeview

我有一个带有复选框的树视图,我有“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变量来检查和设置,这似乎有些迟钝。

4 个答案:

答案 0 :(得分:6)

使用:if(e.Action != TreeViewAction.Unknown)代替if (!_isCheckingInProgress)。请参阅TreeViewAction

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

MSDN将此作为TreeView.AfterCheck Event的示例代码。

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

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

答案 1 :(得分:4)

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

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

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

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

答案 2 :(得分:2)

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

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;
}

答案 3 :(得分:1)

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

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