Como executo o código APÓS o carregamento de um formulário?

126

No .NET, o Windows Forms tem um evento que é acionado antes do carregamento do Formulário (Form.Load), mas não há nenhum evento correspondente que é acionado APÓS o carregamento do formulário. Eu gostaria de executar alguma lógica após o carregamento do formulário.

Alguém pode aconselhar sobre uma solução?

adeel825
fonte
Embora essa pergunta tenha respostas muito boas, vale a pena mencionar isso: docs.microsoft.com/en-us/dotnet/framework/winforms/…
Rishav

Respostas:

192

Você pode usar o evento "Mostrado": MSDN - Form.Shown

"O evento Mostrado é gerado apenas na primeira vez que um formulário é exibido; subsequentemente, minimizar, maximizar, restaurar, ocultar, mostrar ou invalidar e repintar não aumentará esse evento."

Matthias Schippling
fonte
10
Para mim, parece que o manipulador mostrado é executado enquanto o formulário está carregando ... estou errado?
22413 ckonig
3
Velho mas dourado ... Sim, você está errado. A GUI não pode executar tarefas paralelas, o que é importante fazer algo ENQUANTO outra execução é feita.
Dennis Ziolkowski
2
Se no manipulador de eventos Load houver um código que chama Application.DoEvents (), o evento Shown será acionado antes que os manipuladores de eventos Load concluam sua execução. Isso ocorre porque o evento Shown é, de fato, colocado em uma fila de mensagens usando Form.BeginInvoke (ShownEvent) e DoEvents () o força a disparar antes que o Load seja concluído.
Artemix
1
Não foi o suficiente para não funcionar para mim, em c #. Eu tive que adicionar Shown += Form1_Shown;como sugerido em outro tópico
ocramot
11
você deve adicionar This.Refresh (); dentro do evento exibido pela primeira vez antes de sua lógica e vai manter e atualizar a forma de totalmente carregado antes de sua lógica começar a correr
Aylian Craspa
49

Às vezes eu uso (no Load)

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

ou

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

(altere "this" para sua variável de formulário se você estiver manipulando o evento em uma instância diferente de "this").

Isso envia a chamada para o loop do Windows Forms, para que seja processada quando o formulário estiver processando a fila de mensagens.

[atualizado a pedido]

Os métodos Control.Invoke / Control.BeginInvoke destinam-se ao uso com threading e são um mecanismo para enviar trabalho para o thread da interface do usuário. Normalmente, isso é usado por threads de trabalho, etc. Control.Invoke faz uma chamada síncrona, enquanto Control.BeginInvoke faz uma chamada assíncrona.

Normalmente, eles seriam usados ​​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;
  });
}

Isso é feito empurrando uma mensagem para a fila de mensagens do Windows; o thread da interface do usuário (em algum momento) remove a fila da mensagem, processa o delegado e sinaliza ao trabalhador que ela foi concluída ... até agora tudo bem ;-p

ESTÁ BEM; então o que acontece se usarmos Control.Invoke / Control.BeginInvoke no thread da interface do usuário? Ele lida ... se você chamar Control.Invoke, é sensato o suficiente saber que o bloqueio na fila de mensagens causaria um impasse imediato - portanto, se você já estiver no thread da interface do usuário, ele simplesmente executará o código imediatamente ... não nos ajuda ...

Mas Control.BeginInvoke funciona de maneira diferente: ele sempre envia trabalho para a fila, mesmo que já estejamos no thread da interface do usuário. Isso faz uma maneira realmente simples de dizer "em um momento", mas sem a inconveniência de temporizadores, etc (que ainda precisariam fazer a mesma coisa!).

Marc Gravell
fonte
1
Não entendi completamente esse. Você pode explicar um pouco mais?
Torbjørn
Olá, é possível tornar o formulário responsivo enquanto o processo é concluído, chamado BeginInvoke ??
HuMpty duMpty
o que é equivalente no WPF?
mrid
6

Na primeira vez que NÃO iniciará o "AfterLoading",
apenas o registrará para iniciar o 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
fonte
5

Eu tive o mesmo problema e resolvi-o da seguinte maneira:

Na verdade, quero mostrar a mensagem e fechá-la automaticamente após 2 segundos. Para isso eu tive que gerar (dinamicamente) um formulário simples e um rótulo mostrando a mensagem, pare a mensagem por 1500 ms para que o usuário a leia. E Fechar formulário criado dinamicamente. Evento mostrado ocorrer Após o evento de carregamento. Então, o código é

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

Você também pode tentar colocar seu código no evento Ativado do formulário, se desejar que ele ocorra exatamente quando o formulário estiver ativado. Você precisaria colocar uma verificação booleana "executou", se ela deveria ser executada apenas na primeira ativação.

Mitchel Sellers
fonte
1

Essa é uma pergunta antiga e depende mais de quando você precisa iniciar suas rotinas. Como ninguém deseja uma exceção de referência nula, é sempre melhor procurar nulo primeiro e depois usar conforme necessário; só isso pode lhe poupar muita dor.

O motivo mais comum para esse tipo de pergunta é quando um contêiner ou tipo de controle personalizado tenta acessar propriedades inicializadas fora de uma classe personalizada em que essas propriedades ainda não foram inicializadas, causando potencialmente o preenchimento de valores nulos e pode até causar exceções de referência nulas em tipos de objetos. Isso significa que sua classe está sendo executada antes de ser totalmente inicializada - antes de concluir a configuração de suas propriedades etc. Outro possível motivo para esse tipo de pergunta é quando executar gráficos personalizados.

Para melhor responder à pergunta sobre quando iniciar a execução do código após o evento de carregamento de formulário, é necessário monitorar a mensagem WM_Paint ou conectar-se diretamente ao próprio evento de pintura. Por quê? O evento de pintura é acionado somente quando todos os módulos foram totalmente carregados em relação ao evento de carregamento de formulário. Nota: This.visible == true nem sempre é verdadeiro quando é definido como true, portanto não é utilizado para esse fim, exceto para ocultar um formulário.

A seguir, é apresentado um exemplo completo de como iniciar a execução do código após o evento de carregamento do formulário. É recomendável que você não amarre desnecessariamente o loop de mensagem de pintura, portanto, criaremos um evento que começará a executar seu código fora desse loop.

using System.Windows.Forms;

namespace 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
fonte
Isso parece inacreditavelmente longo e tem alguma vantagem sobre simplesmente capturar o evento Mostrado?
Steve Smith
0

Eu sei que este é um post antigo. Mas aqui está como eu fiz isso:

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

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

Você pode fechar seu formulário após alguma execução.

//YourForm.ActiveForm.Close ();

    LoadingForm.ActiveForm.Close();
E Coder
fonte