Frage

Ich habe eine Windows Form-Anwendung, die eine Gemeinschafts-Klasse verwendet, alle gemeinsamen Objekte für die Anwendung zu beherbergen. Die Einstellungen Klasse verfügt über eine Sammlung von Objekten, die Dinge regelmäßig tun, und dann ist da noch etwas von Interesse, sie brauchen die Hauptform aufmerksam zu machen und haben es aktualisieren.

Ich mache zur Zeit dies durch Veranstaltungen auf den Objekten, und wenn jedes Objekt erstellt wird, füge ich einen Eventhandler, um das Ereignis zu dem Formular Karten zurück. Aber ich renne in einige Schwierigkeiten, die diese Anforderungen nicht immer enden auf der Haupt Kopie meiner Form schlägt vor, dass. Zum Beispiel hat mein Formular einen Benachrichtigungs Tray-Icon, aber wenn die Form und Ereignis erfaßt und versucht, eine Blase angezeigt wird, erscheint keine Blase. Allerdings, wenn ich diesen Code ändern, um das Symbol sichtbar zu machen (obwohl es ohnehin schon ist), und dann die Blase angezeigt werden, ein zweites Symbol erscheint und zeigt die Blase richtig.

Hat jemand, bevor sie in diese laufen? Gibt es eine Möglichkeit, dass ich alle meine Ereignisse zwingen kann, durch die einzelne Instanz der Form erfasst werden, oder gibt es eine ganz andere Art und Weise zu handhaben? Ich kann Code-Beispiele bei Bedarf veröffentlichen, aber ich denke, es ist ein gemeinsames Problem Threading.

Weitere Informationen: Ich bin derzeit Me.InvokeRequired in den Event-Handler auf meinem Formular, und es gibt immer FALSCH in diesem Fall. Auch das zweite Tray-Icon erstellt, wenn ich es sichtbar von dieser Form mache kein Kontextmenü hat auf sie, während das „echte“ Symbol tut - tut das clue jemand in

Ich werde mir die Haare ziehen! Dies kann nicht so schwer sein!

SOLUTION : Danke für den Hinweis auf nobugz, und es mich an den Code führt ich jetzt benutze (was schön funktioniert, obwohl ich nicht helfen kann, zu denken gibt es einen besseren Weg, dies zu tun ). Ich habe eine private boolean Variable in der Form „IsPrimary“ genannt und hinzugefügt, um den folgenden Code in das Formular Konstruktor:

    Public Sub New()
        If My.Application.OpenForms(0).Equals(Me) Then
            Me.IsFirstForm = True
        End If
    End Sub

Wenn diese Variable gesetzt und der Konstruktor beendet, es leitet direkt an den Ereignishandler, und ich mit ihnen umgehen auf diese Weise (CAVEAT: Da das Formular für die ich suche, ist die primäre Form für die Anwendung, My.Application . .OpenForms (0) wird, was ich brauche, wenn ich zum ersten Instanz eines nicht-Startformular suchen, würde ich durchlaufen haben, bis ich es gefunden):

    Public Sub EventHandler()
        If Not IsFirstForm Then
            Dim f As Form1 = My.Application.OpenForms(0)
            f.EventHandler()
            Me.Close()
        ElseIf InvokeRequired Then
            Me.Invoke(New HandlerDelegate(AddressOf EventHandler))
        Else
            ' Do your event handling code '
        End If
    End Sub

Zuerst prüft es, ob es auf der richtigen Form läuft - wenn es nicht ist, dann die richtige Form nennen. Dann prüft er, ob der Faden korrekt ist, und ruft den UI-Thread, wenn es nicht. Dann läuft es den Ereigniscode. Ich mag es nicht, dass es möglicherweise drei Anrufe, aber ich kann mich an einem anderen Weg, es zu tun. Es scheint gut zu funktionieren, obwohl es ein wenig umständlich ist. Wenn jemand einen besseren Weg, hat es zu tun, würde ich gerne hören!

Nochmals vielen Dank für all die Hilfe - das würde mich verrückt fahren

War es hilfreich?

Lösung

Ich denke, es ist auch ein Einfädeln Problem. Sind Sie mit Control.Invoke () in der Event-Handler? .NET fängt in der Regel Verletzungen, wenn Sie die App debuggen, aber es gibt Fälle, es kann nicht. NotifyIcon einer von ihnen ist, gibt es keinen Fenstergriff Thread Affinität zu überprüfen.

Bearbeiten nach OP geänderte Frage:

Ein klassischer VB.NET-Trap ist eine Form Instanz durch seine Typnamen zu verweisen. Wie Form1.NotifyIcon1.Something. Das funktioniert nicht wie erwartet, wenn Sie Threading verwenden. Es wird eine neue Instanz der Klasse Form1 erstellen, nicht die vorhandene Instanz verwenden. Das Beispiel ist nicht sichtbar (Show () wurde nie genannt) und ist ansonsten mausetot, da es auf Thread ausgeführt wird, die keine Nachrichtenschleife pumpt. ein zweites Symbol zu sehen, erscheint ein toter Give-away. So wird immer InvokeRequired = False, wenn Sie wissen, dass Sie es von einem Thread verwenden.

Sie müssen einen Verweis auf die bestehende Formularinstanz verwenden. Wenn das schwer zu bekommen ist (Sie in der Regel passieren „Me“ als Argument für den Konstruktor der Klasse) können Sie Application.OpenForms verwenden:

  Dim main As Form1 = CType(Application.OpenForms(0), Form1)
  if (main.InvokeRequired)
    ' etc...

Andere Tipps

Verwenden Control.InvokeRequired, um zu bestimmen, ob Sie auf den entsprechenden Thread sind, verwenden Sie dann Control.Invoke wenn Sie nicht.

Sie sollten für die Invoke-Methode auf dem Formular in der Dokumentation suchen. Es ermöglicht Ihnen, den Code zu machen, führen Sie das Formular auf dem Thread aktualisiert, die die Form besitzt, (was sie tun müssen, Windows-Formulare sind nicht Thread-sicher). So etwas wie Privat Delegate Sub UpdateStatusDelegate (ByVal newStatus als String)

öffentliches Unterupdate (ByVal newStatus als String) Wenn Me.InvokeRequired Dann Dim d As New UpdateStatusDelegate (AddressOf Update) Me.Invoke (d, neues Objekt () {} newStatus) Sonst ‚Update des Formularstatus End If

Wenn Sie einig Beispiel-Code zur Verfügung stellen würde ich mich freue ein maßgeschneidertes Beispiel zur Verfügung zu stellen.

Bearbeiten nach OP sagte sie InvokeRequired verwenden.

Vor InvokeRequired rufen, überprüfen Sie, dass das Formular Handle erstellt wurde, gibt es eine Handle Eigenschaft ist ich glaube. InvokeRequired gibt immer false zurück, wenn die Steuerung im Moment keinen Griff hat, würde dies dann bedeuten, der Code nicht sicher ist, fädelt, obwohl Sie das Richtige getan zu haben, um es so zu machen. Aktualisieren Sie Ihre Frage, wenn Sie herausfinden. Einige Beispielcode wäre zu hilfreich sein.

in c # sieht es wie folgt aus:

private EventHandler StatusHandler = new EventHandler(eventHandlerCode)
void eventHandlerCode(object sender, EventArgs e)
    {
        if (this.InvokeRequired)
        {
            this.Invoke(StatusHandler, sender, e);
        }
        else
        {
          //do work
        }
    }
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top