Come eseguo il codice DOPO il caricamento di un modulo?


126

In .NET, Windows Form dispone di un evento che viene generato prima del caricamento del modulo (Form.Load), ma non è presente alcun evento corrispondente che viene generato DOPO il caricamento del modulo. Vorrei eseguire una logica dopo che il modulo è stato caricato.

Qualcuno può consigliare una soluzione?


Sebbene questa domanda abbia risposte molto buone, potrebbe valere la pena menzionarla: docs.microsoft.com/en-us/dotnet/framework/winforms/…
Rishav

Risposte:


192

È possibile utilizzare l'evento "Shown": MSDN - Form.Shown

"L'evento Shown viene generato solo la prima volta che viene visualizzato un modulo; successivamente ridurre a icona, massimizzare, ripristinare, nascondere, mostrare o invalidare e ridipingere non genererà questo evento."


10
A me sembra che il gestore mostrato venga eseguito DURANTE il caricamento del form ... mi sbaglio?
ckonig

3
Vecchio ma d'oro ... Sì, ti sbagli. La GUI non può eseguire attività parallele, cosa è importante fare qualcosa MENTRE viene eseguita un'altra esecuzione.
Dennis Ziolkowski

2
Se nel gestore dell'evento Load è presente un codice che chiama Application.DoEvents (), l'evento Shown viene generato prima che i gestori dell'evento Load terminino la loro esecuzione. Questo perché l'evento Shown viene infatti inserito in una coda di messaggi utilizzando Form.BeginInvoke (ShownEvent) e DoEvents () ne forza l'attivazione prima del termine del caricamento.
Artemix

1
Non era abbastanza non funzionare per me, in C #. Ho dovuto aggiungere Shown += Form1_Shown;come suggerito in un altro thread
ocramot

11
dovresti aggiungere This.Refresh (); all'interno dell'evento Mostrato prima della tua logica e manterrà e aggiornerà il modulo per caricarlo completamente prima che la tua logica inizi a funzionare
Aylian Craspa

49

A volte uso (in Load)

this.BeginInvoke((MethodInvoker) delegate {
  // some code
});

o

this.BeginInvoke((MethodInvoker) this.SomeMethod);

(cambia "this" nella variabile del modulo se gestisci l'evento su un'istanza diversa da "this").

Questo inserisce l'invoke nel ciclo di windows-forms, quindi viene elaborato quando il modulo sta elaborando la coda dei messaggi.

[aggiornato su richiesta]

I metodi Control.Invoke / Control.BeginInvoke sono destinati all'uso con il threading e sono un meccanismo per inviare il lavoro al thread dell'interfaccia utente. Normalmente viene utilizzato dai thread di lavoro, ecc. Control.Invoke esegue una chiamata sincrona, mentre Control.BeginInvoke esegue una chiamata asincrona.

Normalmente, questi sarebbero usati come:

SomeCodeOrEventHandlerOnAWorkerThread()
{
  // this code running on a worker thread...
  string newText = ExpensiveMethod(); // perhaps a DB/web call

  // now ask the UI thread to update itself
  this.Invoke((MethodInvoker) delegate {
      // this code runs on the UI thread!
      this.Text = newText;
  });
}

Lo fa inserendo un messaggio nella coda dei messaggi di Windows; il thread dell'interfaccia utente (a un certo punto) rimuove il messaggio dalla coda, elabora il delegato e segnala al lavoratore che è stato completato ... finora tutto bene ;-p

OK; quindi cosa succede se usiamo Control.Invoke / Control.BeginInvoke sul thread dell'interfaccia utente? Affronta ... se chiami Control.Invoke, è abbastanza sensato sapere che il blocco sulla coda dei messaggi causerebbe un deadlock immediato, quindi se sei già sul thread dell'interfaccia utente esegue semplicemente il codice immediatamente ... in modo che non ci aiuta ...

Ma Control.BeginInvoke funziona in modo diverso: spinge sempre il lavoro in coda, anche se siamo già nel thread dell'interfaccia utente. Questo rende un modo davvero semplice per dire "in un momento", ma senza l'inconveniente dei timer ecc (che dovrebbero comunque fare la stessa cosa!).


1
Non l'ho capito completamente. Puoi spiegare un po 'di più?
Torbjørn

Ciao mark, è possibile rendere il modulo reattivo mentre il processo è completo, chiamato in BeginInvoke ??
huMpty duMpty

qual è l'equivalente in WPF?
mrid

6

La prima volta che NON avvierà "AfterLoading", lo
registrerà solo per avviare il caricamento successivo.

private void Main_Load(object sender, System.EventArgs e)
{
    //Register it to Start in Load 
    //Starting from the Next time.
    this.Activated += AfterLoading;
}

private void AfterLoading(object sender, EventArgs e)
{
    this.Activated -= AfterLoading;
    //Write your code here.
}

5

Ho avuto lo stesso problema e l'ho risolto come segue:

In realtà voglio mostrare il messaggio e chiuderlo automaticamente dopo 2 secondi. Per questo ho dovuto generare (dinamicamente) un modulo semplice e un'etichetta che mostra il messaggio, interrompere il messaggio per 1500 ms in modo che l'utente lo leggesse. E chiudere il modulo creato dinamicamente. L'evento mostrato si verifica dopo l'evento di caricamento. Quindi il codice è

Form MessageForm = new Form();
MessageForm.Shown += (s, e1) => { 
    Thread t = new Thread(() => Thread.Sleep(1500)); 
    t.Start(); 
    t.Join(); 
    MessageForm.Close(); 
};

2

Puoi anche provare a inserire il tuo codice nell'evento Attivato del modulo, se vuoi che si verifichi, proprio quando il modulo è attivato. Dovresti inserire un controllo booleano "ha eseguito" anche se dovrebbe essere eseguito solo alla prima attivazione.


1

Questa è una vecchia domanda e dipende più da quando è necessario iniziare la routine. Dal momento che nessuno vuole un'eccezione di riferimento nullo, è sempre meglio controllare prima se nullo e poi usarlo secondo necessità; questo da solo può farti risparmiare un sacco di dolore.

Il motivo più comune per questo tipo di domanda è quando un contenitore o un tipo di controllo personalizzato tenta di accedere a proprietà inizializzate al di fuori di una classe personalizzata in cui tali proprietà non sono state ancora inizializzate, causando potenzialmente la compilazione di valori nulli e può persino causare eccezioni di riferimento nullo sui tipi di oggetto. Significa che la tua classe è in esecuzione prima di essere completamente inizializzata - prima che tu abbia finito di impostare le tue proprietà, ecc. Un'altra possibile ragione per questo tipo di domanda è quando eseguire la grafica personalizzata.

Per rispondere al meglio alla domanda su quando iniziare a eseguire il codice dopo l'evento di caricamento del modulo, è necessario monitorare il messaggio WM_Paint o collegarsi direttamente all'evento paint stesso. Perché? L'evento paint si attiva solo quando tutti i moduli sono stati caricati completamente rispetto all'evento di caricamento del modulo. Nota: This.visible == true non è sempre vero quando è impostato su true, quindi non viene utilizzato affatto per questo scopo tranne che per nascondere un modulo.

Di seguito è riportato un esempio completo di come avviare l'esecuzione del codice in seguito all'evento di caricamento del modulo. Si consiglia di non legare inutilmente il ciclo dei messaggi paint, quindi creeremo un evento che inizierà l'esecuzione del codice al di fuori di quel ciclo.

using System.Windows.Forms;

spazio dei nomi MyProgramStartingPlaceExample {

/// <summary>
/// Main UI form object
/// </summary>
public class Form1 : Form
{

    /// <summary>
    /// Main form load event handler
    /// </summary>
    public Form1()
    {
        // Initialize ONLY. Setup your controls and form parameters here. Custom controls should wait for "FormReady" before starting up too.
        this.Text = "My Program title before form loaded";
        // Size need to see text. lol
        this.Width = 420;

        // Setup the sub or fucntion that will handle your "start up" routine
        this.StartUpEvent += StartUPRoutine;

        // Optional: Custom control simulation startup sequence:
        // Define your class or control in variable. ie. var MyControlClass new CustomControl;
        // Setup your parameters only. ie. CustomControl.size = new size(420, 966); Do not validate during initialization wait until "FormReady" is set to avoid possible null values etc. 
        // Inside your control or class have a property and assign it as bool FormReady - do not validate anything until it is true and you'll be good! 
    }

    /// <summary>
    /// The main entry point for the application which sets security permissions when set.
    /// </summary>
    static void Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new Form1());
    }


    #region "WM_Paint event hooking with StartUpEvent"            
    //
    // Create a delegate for our "StartUpEvent"
    public delegate void StartUpHandler();
    //
    // Create our event handle "StartUpEvent"
    public event StartUpHandler StartUpEvent;
    //
    // Our FormReady will only be set once just he way we intendded
    // Since it is a global variable we can poll it else where as well to determine if we should begin code execution !!
    bool FormReady;
    //
    // The WM_Paint message handler: Used mostly to paint nice things to controls and screen
    protected override void OnPaint(PaintEventArgs e)
    {
        // Check if Form is ready for our code ?
        if (FormReady == false) // Place a break point here to see the initialized version of the title on the form window
        {
            // We only want this to occur once for our purpose here.
            FormReady = true;
            //
            // Fire the start up event which then will call our "StartUPRoutine" below.
            StartUpEvent();
        }
        //
        // Always call base methods unless overriding the entire fucntion
        base.OnPaint(e);
    }
    #endregion


    #region "Your StartUp event Entry point"
    //
    // Begin executuing your code here to validate properties etc. and to run your program. Enjoy!
    // Entry point is just following the very first WM_Paint message - an ideal starting place following form load
    void StartUPRoutine()
    {
        // Replace the initialized text with the following
        this.Text = "Your Code has executed after the form's load event";
        //
        // Anyway this is the momment when the form is fully loaded and ready to go - you can also use these methods for your classes to synchronize excecution using easy modifications yet here is a good starting point. 
        // Option: Set FormReady to your controls manulaly ie. CustomControl.FormReady = true; or subscribe to the StartUpEvent event inside your class and use that as your entry point for validating and unleashing its code.
        //
        // Many options: The rest is up to you!
    }
    #endregion

}

}


Questo sembra incredibilmente prolisso, e ha dei vantaggi rispetto al semplice vedere l'evento mostrato?
Steve Smith

0

So che questo è un vecchio post. Ma ecco come l'ho fatto:

    public Form1(string myFile)
    {
        InitializeComponent();
        this.Show();
        if (myFile != null)
        {
            OpenFile(myFile);
        }
    }

    private void OpenFile(string myFile = null)
    {
            MessageBox.Show(myFile);
    }

-9

Puoi chiudere il modulo dopo qualche esecuzione ..

//YourForm.ActiveForm.Close ();

    LoadingForm.ActiveForm.Close();
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.