2008-10-20 14 views
96

En .NET, Windows Forms tiene un evento que se dispara antes de que se cargue el Formulario (Form.Load), pero no hay un evento correspondiente que se desencadena DESPUÉS de que se haya cargado el formulario. Me gustaría ejecutar algo de lógica después de que se haya cargado el formulario.¿Cómo ejecuto el código DESPUÉS de que se haya cargado un formulario?

¿Alguien puede aconsejarle sobre una solución?

Respuesta

149

Se podría utilizar la "muestra" evento: MSDN - Form.Shown

"El evento que se muestra es sólo fue planteada por primera vez se muestra un formulario; posteriormente minimizar, maximizar, restaurar, ocultar, mostrar, o invalidar y volver a pintar no lo hará plantear este evento ".

+9

Para mí, parece que el controlador mostrado se ejecuta MIENTRAS el formulario se está cargando ... ¿estoy equivocado? – ckonig

+3

Viejo pero dorado ... Sí, estás equivocado. GUI no puede ejecutar tareas paralelas, lo que es importante hacer algo MIENTRAS se hace otra ejecución. –

+1

Si en el controlador de eventos Load hay un código que llama a Application.DoEvents(), el evento Shown se desencadena antes de que los controladores de eventos de Load finalicen su ejecución. Esto se debe a que el evento Mostrado se coloca en una cola de mensajes usando Form.BeginInvoke (ShownEvent) y DoEvents() lo fuerza a disparar antes de que termine Load. – Artemix

43

veces uso (en carga)

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

o

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

(cambio de "esto" a la variable de formulario si usted está manejando el caso en una instancia que no sea "este") .

Esto activa la invocación en el bucle de Windows forms, por lo que se procesa cuando el formulario procesa la cola de mensajes.

[Actualizado a petición]

Los métodos Control.Invoke/Control.BeginInvoke están destinados para su uso con roscado, y son un mecanismo para empujar el trabajo sobre la rosca UI. Normalmente esto lo utilizan los hilos de trabajo, etc. Control.Invoke realiza una llamada síncrona, mientras que Control.BeginInvoke realiza una llamada asíncrona.

Normalmente, éstos se utilizaría como:

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

Para ello, empujando un mensaje en la cola de mensajes ventanas; el subproceso de interfaz de usuario (en algún punto) elimina la cola del mensaje, procesa al delegado y le indica al trabajador que lo completó ... hasta ahora todo bien ;-p

Aceptar; Entonces, ¿qué ocurre si utilizamos Control.Invoke/Control.BeginInvoke en el hilo de la interfaz de usuario? Resuelve ... si llama a Control.Invoke, es lo suficientemente sensible como para saber que el bloqueo en la cola de mensajes provocaría un punto muerto inmediato, por lo que si ya está en el hilo de la interfaz de usuario simplemente ejecuta el código inmediatamente ... para que no nos ayuda ...

Pero Control.BeginInvoke funciona de manera diferente: siempre empuja el trabajo a la cola, incluso si ya estamos en el hilo de la interfaz de usuario. Esto hace una forma muy simple de decir "en un momento", pero sin la inconveniencia de los temporizadores, etc. (¡lo que igual tendría que hacer lo mismo de todos modos!).

+2

uno de los buenos Marc Gravell. Un truco más para la bolsa;) –

+1

No lo entendí por completo. ¿Puedes explicar un poco más? –

+0

Hola marca, ¿es posible hacer que la forma responda mientras se completa el proceso que se llama en BeginInvoke? –

2

También podría intentar poner su código en el evento Activado del formulario, si lo desea, justo cuando se activa el formulario. Debería ingresar un chequeo booleano "ejecutado" aunque solo se suponga que se ejecute en la primera activación.

6

que tenían el mismo problema y lo resolvió de la siguiente manera:

En realidad quiero mostrar mensajes y cerrarla automáticamente después de 2 segundos. Para eso tuve que generar (dinámicamente) formulario simple y una etiqueta que mostraba el mensaje, detener el mensaje por 1500 ms para que el usuario lo leyera. Y Cerrar formulario creado dinámicamente. Se muestra el evento mostrado después del evento de carga.Así código es

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

Puede cerrar su forma después de una ejecución ..

//YourForm.ActiveForm.Close();

LoadingForm.ActiveForm.Close(); 
2

La primera vez él no se iniciará "carga diferida",
se acaba de registrar para iniciar la siguiente carga.

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. 
} 
+0

¡esto causa un ciclo sin fin! – Dwza

+0

No, no causará que anule la suscripción al evento en el método AfterLoading –

+0

Supongo que mi comentario apuntaba a una versión anterior de su publicación ... su última edición fue 'editada el 20 de julio a las 7:20 'y mi el comentario fue '4 de agosto '16 a las 15:54' casi 1 año antes ... – Dwza

0

Esta es una pregunta anterior y depende más de cuándo necesite comenzar sus rutinas. Como nadie quiere una excepción de referencia nula, siempre es mejor verificar primero la nula y luego usarla según sea necesario; eso solo puede ahorrarle mucha pena. El motivo más común para este tipo de pregunta es cuando un contenedor o tipo de control personalizado intenta acceder a propiedades inicializadas fuera de una clase personalizada donde esas propiedades aún no se han inicializado, lo que puede ocasionar que se llenen valores nulos e incluso puede causar una referencia nula excepciones en tipos de objetos. Significa que su clase se está ejecutando antes de que se haya inicializado por completo, antes de que haya terminado de configurar sus propiedades, etc. Otra posible razón para este tipo de pregunta es cuándo realizar gráficos personalizados.

Para responder mejor a la pregunta sobre cuándo comenzar la ejecución del código después del evento de carga de formulario, es supervisar el mensaje WM_Paint o enganchar directamente en el evento paint. ¿Por qué? El evento de pintura solo se activa cuando todos los módulos se han cargado por completo con respecto a su evento de carga de formulario. Nota: This.visible == true no siempre es verdadero cuando se establece como verdadero, por lo que no se usa en absoluto para este fin, excepto para ocultar un formulario.

El siguiente es un ejemplo completo de cómo comenzar a ejecutar el código siguiendo el evento de carga de formulario. Se recomienda no vincular innecesariamente el bucle de mensajes de pintura, por lo que crearemos un evento que comenzará a ejecutar el código fuera de ese bucle.

using System.Windows.Forms; 

espacio de nombres 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 

} 

}

Cuestiones relacionadas