¿Cómo ejecuto el código DESPUÉS de que se haya cargado un formulario?

126

En .NET, los formularios de Windows tienen un evento que se dispara antes de que se cargue el formulario (Form.Load), pero no hay ningún evento correspondiente que se dispare 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.

¿Alguien puede aconsejar sobre una solución?

adeel825
fuente
Aunque esta pregunta tiene muy buenas respuestas, vale la pena mencionar esto: docs.microsoft.com/en-us/dotnet/framework/winforms/…
Rishav

Respuestas:

192

Puede usar el evento "Mostrado": MSDN - Form.Shown

"El evento Mostrado solo se genera la primera vez que se muestra un formulario; posteriormente, minimizar, maximizar, restaurar, ocultar, mostrar o invalidar y volver a pintar no generará este evento".

Matthias Schippling
fuente
10
Para mí, parece que el controlador que se muestra se ejecuta MIENTRAS se carga el formulario ... ¿estoy equivocado?
ckonig
3
Viejo pero dorado ... Sí, estás equivocado. La GUI no puede ejecutar tareas paralelas, lo que es importante hacer algo MIENTRAS se realiza otra ejecución.
Dennis Ziolkowski
2
Si en el controlador de eventos Load hay un código que llama a Application.DoEvents (), el evento Shown se activa antes de que los controladores de eventos Load finalicen su ejecución. Esto se debe a que el evento Shown se coloca en una cola de mensajes usando Form.BeginInvoke (ShownEvent) y DoEvents () lo obliga a dispararse antes de que finalice la carga.
Artemix
1
No fue suficiente no funciona para mí, en C #. Tuve que agregar Shown += Form1_Shown;como se sugiere en otro hilo
ocramot
11
debe agregar This.Refresh (); dentro del evento Mostrado primero antes de su lógica y mantendrá y actualizará el formulario para que esté completamente cargado antes de que su lógica comience a ejecutarse
Aylian Craspa
49

A veces uso (en carga)

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

o

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

(cambie "this" a su variable de formulario si está manejando el evento en una instancia que no sea "this").

Esto empuja la invocación al bucle de formularios de Windows, por lo que se procesa cuando el formulario está procesando la cola de mensajes.

[actualizado a pedido]

Los métodos Control.Invoke / Control.BeginInvoke están diseñados para usarse con subprocesos y son un mecanismo para impulsar el trabajo en el subproceso de la interfaz de usuario. Normalmente esto es utilizado por subprocesos de trabajo, etc. Control.Invoke hace una llamada síncrona, mientras que Control.BeginInvoke hace una llamada asíncrona.

Normalmente, estos se usarían 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;
  });
}

Lo hace al insertar un mensaje en la cola de mensajes de Windows; el subproceso de la interfaz de usuario (en algún momento) quita la cola del mensaje, procesa al delegado y le indica al trabajador que se completó ... hasta ahora todo bien ;-p

OKAY; Entonces, ¿qué sucede si usamos Control.Invoke / Control.BeginInvoke en el hilo de la interfaz de usuario? Hace frente ... si llama a Control. Invocar, 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 de inmediato ... 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 es una forma realmente simple de decir "en un momento", pero sin los inconvenientes de los temporizadores, etc. (¡que de todos modos tendrían que hacer lo mismo!).

Marc Gravell
fuente
1
No entendí completamente eso. ¿Puedes explicar un poco más?
Torbjørn
Hola Mark, ¿es posible hacer que el formulario responda mientras se completa el proceso que se llama en BeginInvoke?
huMpty duMpty
¿Qué es equivalente en WPF?
mrid
6

La primera vez NO comenzará "AfterLoading",
simplemente lo registrará para iniciar NEXT Load.

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.
}
Ahmed Sabry
fuente
5

Tuve el mismo problema y lo resolví de la siguiente manera:

En realidad, quiero mostrar el mensaje y cerrarlo automáticamente después de 2 segundos. Para eso tuve que generar (dinámicamente) una forma simple y una etiqueta que muestra el mensaje, detener el mensaje durante 1500 ms para que el usuario lo lea. Y cierre el formulario creado dinámicamente. El evento mostrado ocurre después del evento de carga. Entonces el código es

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

También puede intentar poner su código en el evento Activado del formulario, si desea que ocurra, justo cuando el formulario esté activado. Sin embargo, deberá realizar una comprobación booleana de "se ha ejecutado" si solo se supone que se ejecuta en la primera activación.

Mitchel Sellers
fuente
1

Esta es una pregunta antigua y depende más de cuándo necesita comenzar sus rutinas. Dado que nadie quiere una excepción de referencia nula, siempre es mejor verificar primero nulo y luego usar según sea necesario; eso solo puede ahorrarle mucho dolor.

La razón más común para este tipo de pregunta es cuando un contenedor o un 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 causar que se llenen valores nulos e incluso puede causar excepciones de referencia nulas en tipos de objeto. 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 preguntas es cuándo realizar gráficos personalizados.

Para responder mejor a la pregunta sobre cuándo comenzar a ejecutar el código después del evento de carga del formulario es monitorear el mensaje WM_Paint o conectarse directamente al evento de pintura en sí. ¿Por qué? El evento de pintura solo se activa cuando todos los módulos se han cargado completamente con respecto a su evento de carga de formulario. Nota: This.visible == true no siempre es cierto cuando se establece true, por lo que no se utiliza para este propósito, excepto para ocultar un formulario.

El siguiente es un ejemplo completo de cómo comenzar a ejecutar su código después del evento de carga del formulario. Se recomienda que no ate innecesariamente el bucle de mensajes de pintura, por lo que crearemos un evento que comenzará a ejecutar su 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

}

}

Jamie
fuente
Esto parece increíblemente largo, y ¿tiene alguna ventaja sobre simplemente ver el evento Shown?
Steve Smith, el
0

Sé que esta es una publicación anterior. Pero así es como lo he hecho:

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

    private void OpenFile(string myFile = null)
    {
            MessageBox.Show(myFile);
    }
J. Fischlein
fuente
-9

Puede cerrar su formulario después de alguna ejecución.

//YourForm.ActiveForm.Close ();

    LoadingForm.ActiveForm.Close();
E codificador
fuente