6 Stimmen

Wie kann ich verhindern, dass ein Ereignis seine eigene Veranstaltung von Auslösen in C# verursacht?

Ich habe eine Baumansicht mit Kontrollkästchen und ich habe den folgenden Handler für das Ereignis "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();
        }
    }
}

Wenn Sie genau hinsehen, werden Sie sehen, dass ich prüfe, ob "_isCheckingInProgress". Wenn dies nicht der Fall ist, fahre ich fort, erweitere alle Knoten und rufe die Methode SetChildrenCheckState() auf. Das Problem, auf das ich gestoßen bin, ist, dass SetChildrenCheckState() anschließend dazu führt, dass alle untergeordneten Knoten das AfterCheck-Ereignis für ihren eigenen Knoten auslösen.

Meine Frage ist, gibt es eine saubere Möglichkeit, das erste AfterCheck-Ereignis auslösen, aber nicht die folgenden? Es scheint Art von hackish, dass ich eine Instanz bool-Variable zu überprüfen und zu setzen haben müssen.

8voto

Brian Punkte 24901

Verwendung: if(e.Action != TreeViewAction.Unknown) anstelle von if (!_isCheckingInProgress) . Siehe TreeViewAction .

Wenn der Benutzer die Tastatur oder die Maus benutzt, um die Kästchen anzukreuzen, e.Action wird TreeViewAction.ByKeyboard o TreeViewAction.ByMouse .

Der MSDN stellt dies als Beispielcode für die TreeView.AfterCheck Ereignis .

Edit 1: Wenn Sie das Kontrollkästchen selbst im Code setzen, verschieben Sie den Code im Event-Handler in eine neue Funktion und lassen Sie den Code, der das Kontrollkästchen setzt, diese Funktion direkt aufrufen. Der Sinn dieser Lösung ist, dass Sie Ereignishandler für Benutzereingaben verwenden können, ohne dass diese Ereignisse ausgelöst werden, wenn Sie die Kontrollkästchen selbst per Code setzen.

Edit 2: Siehe die Antwort von Spencer für eine Erklärung meines Kommentars in Edit 1

4voto

Spencer Ruport Punkte 34547

Eine Empfehlung, die Sie gelegentlich in SO sehen werden, ist, nicht viel Code in die Event-Handler selbst zu stecken. Dafür gibt es eine Reihe von Gründen. Erstens wäre es in Ihrem Fall einfacher, einen Aufruf wie:

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

Und den Rest Ihres Codes platzieren Sie in GetAvailableFiles() . Dadurch wird eine Trennung zwischen Ereigniscode und Aktionscode geschaffen, die nach Ansicht der meisten Menschen eine sinnvolle Unterscheidung darstellt.

Zweitens, was in Ihrem Fall zutreffen kann, aber nicht muss, ist, dass mehrere Ereignisse dieselbe Handlung verursachen können. Wie zum Beispiel mnuFileQuit_Click y btnClose_Click als ein offensichtliches Beispiel. Wenn beide Anrufe an CloseApplication() Es wird viel überflüssiger Code entfernt.

2voto

Biff MaGriff Punkte 7991

Ich persönlich verwende eine Funktion, die das Ereignis entfernt und dann hinzufügt.

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

1voto

Cody Gray Punkte 229889

Nein, es gibt keinen saubereren Weg, das zu tun, was Sie gezeigt haben. Ich bin mir nicht ganz sicher, warum Sie glauben, dass Variablen ein "Hack"-Ansatz sind. Das Setzen einer Flagge ist eine gängige Technik, die beim Schreiben von UI-Code verwendet wird.

Der eigentliche Hack wäre eine obskure Methode, um zu verhindern, dass das Ereignis der 第一 Zeit, aber nicht zu einem späteren Zeitpunkt. Künftige Wartungsprogrammierer werden garantiert verstehen, wie das Setzen einer Markierung funktioniert; sie werden die "Eleganz" Ihres alternativen Ansatzes garantiert nicht zu schätzen wissen.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X