Domanda

Ho un'applicazione Windows Form che utilizza una classe condivisa per ospitare tutti gli oggetti comuni per l'applicazione. La classe settings ha una raccolta di oggetti che fanno le cose periodicamente, e poi c'è qualcosa di interessante, hanno bisogno di avvisare il modulo principale e farlo aggiornare.

Attualmente lo sto facendo tramite Eventi sugli oggetti e quando ogni oggetto viene creato, aggiungo un EventHandler per mappare l'evento al modulo. Tuttavia, sto riscontrando alcuni problemi che suggeriscono che queste richieste non finiscono sempre nella copia principale del mio modulo. Ad esempio, il mio modulo ha un'icona nella barra delle notifiche, ma quando il modulo acquisisce ed eventi e tenta di visualizzare una bolla, non viene visualizzata alcuna bolla. Tuttavia, se modifico quel codice per rendere visibile l'icona (anche se lo è già), e quindi visualizzo la bolla, appare una seconda icona che mostra la bolla correttamente.

Qualcuno l'ha mai incontrato prima? C'è un modo in cui posso forzare tutti i miei eventi ad essere catturati dalla singola istanza del modulo o c'è un modo completamente diverso di gestirlo? Posso inviare esempi di codice se necessario, ma sto pensando che sia un problema di threading comune.

ALTRE INFORMAZIONI: Attualmente sto usando Me.InvokeRequired nel gestore eventi nel mio modulo e in questo caso restituisce sempre FALSE. Inoltre, la seconda icona della barra delle applicazioni creata quando la rendo visibile da questo modulo non ha un menu di scelta rapida, mentre il "reale" icona fa - indovina qualcuno?

Ho intenzione di strapparmi i capelli! Questo non può essere così difficile!

SOLUZIONE : grazie a nobugz per l'indizio e mi ha portato al codice che sto usando ora (che funziona magnificamente, anche se non posso fare a meno di pensare che ci sia un modo migliore per farlo ). Ho aggiunto una variabile booleana privata al modulo chiamato " IsPrimary " ;, e ho aggiunto il seguente codice al costruttore del modulo:

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

Una volta impostata questa variabile e il costruttore termina, si dirige direttamente al gestore dell'evento e io la gestisco in questo modo (CAVEAT: Poiché il modulo che sto cercando è il modulo principale per l'applicazione, My.Application .OpenForms (0) ottiene ciò di cui ho bisogno. Se stavo cercando la prima istanza di un modulo non di avvio, dovrei scorrere fino a quando non l'ho trovato):

    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

Innanzitutto, controlla se è in esecuzione nel modulo corretto; in caso contrario, chiama il modulo giusto. Quindi controlla se il thread è corretto e chiama il thread dell'interfaccia utente in caso contrario. Quindi esegue il codice evento. Non mi piace che siano potenzialmente tre chiamate, ma non riesco a pensare a un altro modo per farlo. Sembra funzionare bene, anche se è un po 'ingombrante. Se qualcuno ha un modo migliore per farlo, mi piacerebbe ascoltarlo!

Ancora una volta, grazie per tutto l'aiuto: questo mi avrebbe fatto impazzire!

È stato utile?

Soluzione

Penso che sia anche un problema di threading. Stai usando Control.Invoke () nel gestore di eventi? .NET di solito rileva violazioni quando esegui il debug dell'app ma in alcuni casi non è possibile. NotifyIcon è uno di questi, non esiste un handle di finestra per verificare l'affinità del thread.

Modifica dopo l'OP ha modificato la domanda:

Una trappola classica VB.NET consiste nel fare riferimento a un'istanza Form tramite il nome del tipo. Come Form1.NotifyIcon1.Something. Non funziona come previsto quando si utilizza il threading. Creerà una nuova istanza della classe Form1, non utilizzerà l'istanza esistente. Quell'istanza non è visibile (Show () non è mai stata chiamata) ed è altrimenti morta come una porta perché è in esecuzione su thread che non pompa un ciclo di messaggi. Vedere una seconda icona apparire è un dono morto. Quindi sta ottenendo InvokeRequired = False quando sai che lo stai usando da un thread.

È necessario utilizzare un riferimento all'istanza del modulo esistente. Se è difficile trovarlo (di solito passi " Me " come argomento al costruttore della classe), puoi usare Application.OpenForms:

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

Altri suggerimenti

Usa Control.InvokeRequired per determinare se sei sulla discussione corretta, quindi usa Control.Invoke se non lo sei.

È necessario consultare la documentazione per il metodo Invoke sul modulo. Ti consentirà di eseguire il codice che aggiorna il modulo sul thread proprietario del modulo (cosa che deve fare, i moduli di Windows non sono thread-safe). Qualcosa di simile a Delegato privato Sub UpdateStatusDelegate (ByVal newStatus as String)

PublicState UpdateStatus (ByVal newStatus come String) Se Me.InvokeRequired Quindi Dim d come nuovo UpdateStatusDelegate (AddressOf UpdateStatus) Me.Invoke (d, new Object () {newStatus}) Altro 'Aggiorna lo stato del modulo End If

Se fornisci del codice di esempio, sarei felice di fornire un esempio più personalizzato.

Modifica dopo che OP ha dichiarato di utilizzare InvokeRequired.

Prima di chiamare InvokeRequired, verificare che l'handle del modulo sia stato creato, esiste una proprietà HandleCreated che credo. InvokeRequired restituisce sempre false se al momento il controllo non ha un handle, ciò significherebbe che il codice non è thread-safe anche se hai fatto la cosa giusta per renderlo tale. Aggiorna la tua domanda quando lo scopri. Anche qualche codice di esempio sarebbe utile.

in c # sembra così:

private EventHandler StatusHandler = new EventHandler(eventHandlerCode)
void eventHandlerCode(object sender, EventArgs e)
    {
        if (this.InvokeRequired)
        {
            this.Invoke(StatusHandler, sender, e);
        }
        else
        {
          //do work
        }
    }
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top