簡體   English   中英

如何防止事件導致自己的事件在C#中觸發?

[英]How can I prevent an event from causing its own event from firing in 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。

使用: if(e.Action != TreeViewAction.Unknown)而不是if (!_isCheckingInProgress) 請參見TreeViewAction

當用戶使用鍵盤或鼠標檢查復選框時, e.Action將是TreeViewAction.ByKeyboardTreeViewAction.ByMouse

MSDN將此作為TreeView.AfterCheck事件的示例代碼提供。

編輯1:顯然,如果您在代碼中自己設置復選框,請將事件處理程序中的代碼移動到新函數,並使用設置復選框的代碼直接調用它。 此解決方案的目的是讓您使用事件處理程序進行用戶輸入,而無需在通過代碼自行設置復選框時觸發這些事件。

編輯2:請參閱斯賓塞的答案,以解釋我在編輯1中的評論

偶爾會看到SO的一個建議是不要將大量代碼放入事件處理程序本身。 有許多的原因。 首先,在您的情況下,更容易理解如下調用:

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

並將其余代碼放在GetAvailableFiles() 這在事件代碼和動作代碼之間產生了分離,大多數人都認為這是值得區分的。

其次,在您的情況下可能適用或不適用的是多個事件可能導致相同的操作。 mnuFileQuit_ClickbtnClose_Click作為一個明顯的例子。 如果兩者都調用CloseApplication()它會刪除大量冗余代碼。

就個人而言,我使用一個刪除然后添加事件的函數。

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代碼時常用的技術。

真正的黑客行為將是一種模糊的方式來防止一次發生事件,但不是隨后的時間。 未來的維護程序員可以保證了解設置標志的工作原理; 他們無法保證欣賞您的替代方法的“優雅”。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM