web-dev-qa-db-fra.com

Comment exécuter le code APRES qu'un formulaire ait été chargé?

Dans .NET, les formulaires Windows ont un événement qui se déclenche avant le chargement du formulaire (Form.Load), mais aucun événement correspondant n'est déclenché APRÈS le chargement du formulaire. Je voudrais exécuter une certaine logique après le chargement du formulaire.

Quelqu'un peut-il conseiller sur une solution?

117
adeel825

Vous pouvez utiliser l'événement "Shown": MSDN - Form.Shown

"L'événement indiqué n'est déclenché que la première fois qu'un formulaire est affiché; par la suite, minimiser, agrandir, restaurer, masquer, afficher ou invalider et repeindre ne déclenchera pas cet événement."

175

J'utilise parfois (en charge)

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

ou

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

(changez "ceci" en votre variable de formulaire si vous gérez l'événement sur une instance autre que "ceci").

Cela pousse l'appel sur la boucle windows-forms afin qu'il soit traité lorsque le formulaire traite la file d'attente des messages.

[mis à jour sur demande]

Les méthodes Control.Invoke/Control.BeginInvoke sont conçues pour être utilisées avec le threading et constituent un mécanisme permettant de pousser le travail sur le thread d'interface utilisateur. Normalement, cela est utilisé par les threads de travail, etc. Control.Invoke effectue un appel synchrone, où-comme Control.BeginInvoke effectue un appel asynchrone.

Normalement, ceux-ci seraient utilisés comme:

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

Pour ce faire, il envoie un message dans la file de messages de Windows. le thread d'interface utilisateur (à un moment donné) met en file d'attente le message, traite le délégué et signale au travailleur qu'il a terminé ... jusqu'ici tout va bien ;-p

D'ACCORD; alors que se passe-t-il si nous utilisons Control.Invoke/Control.BeginInvoke sur le thread d'interface utilisateur? Il se débrouille ... si vous appelez Control.Invoke, il est assez judicieux de savoir que le blocage de la file de messages causerait un blocage immédiat - si vous êtes déjà sur le thread d'interface utilisateur, il exécute simplement le code immédiatement ... de sorte que ne nous aide pas ...

Mais Control.BeginInvoke fonctionne différemment: il toujours pousse le travail dans la file d'attente, même si nous sommes déjà sur le thread d'interface utilisateur. C’est une façon très simple de dire "dans un instant", mais sans l’inconvénient des minuteries, etc. (il faudrait quand même faire la même chose!).

45
Marc Gravell

La première fois, il NE commencera PAS "AfterLoading",
Il suffira de l’enregistrer pour lancer 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.
}
6
Ahmed Sabry

J'ai eu le même problème et l'ai résolu comme suit:

En fait, je veux montrer Message et le fermer automatiquement après 2 secondes. Pour cela, je devais générer (dynamiquement) un formulaire simple et une étiquette affichant un message, arrêter le message pendant 1500 ms afin que l'utilisateur le lise. Et fermez le formulaire créé dynamiquement. L'événement montré se produit après l'événement de chargement. Donc le code est

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

Vous pouvez également essayer de placer votre code dans l'événement Activé du formulaire, si vous souhaitez qu'il se produise, au moment où le formulaire est activé. Vous auriez besoin de mettre dans un booléen "a exécuté" vérifier si elle est seulement supposée être exécutée lors de la première activation.

2
Mitchel Sellers

Cette question est ancienne et dépend davantage du moment où vous devez démarrer vos routines. Étant donné que personne ne souhaite d'exception de référence null, il est toujours préférable de vérifier d'abord la valeur null, puis de l'utiliser au besoin. cela seul peut vous épargner beaucoup de chagrin.

La raison la plus courante de ce type de question est lorsqu'un conteneur ou un type de contrôle personnalisé tente d'accéder à des propriétés initialisées en dehors d'une classe personnalisée alors que ces propriétés n'ont pas encore été initialisées, ce qui entraîne potentiellement le remplissage des valeurs NULL et peut même provoquer des exceptions de référence NULL. sur les types d'objets. Cela signifie que votre classe est en cours d'exécution avant son initialisation complète, avant que vous ayez fini de définir vos propriétés, etc. Une autre raison possible de ce type de question est de savoir quand exécuter des graphiques personnalisés.

Pour mieux répondre à la question de savoir quand commencer à exécuter le code après l'événement de chargement de formulaire, vous devez surveiller le message WM_Paint ou le connecter directement à l'événement Paint lui-même. Pourquoi? L'événement Paint ne se déclenche que lorsque tous les modules ont été complètement chargés en ce qui concerne votre événement de chargement de formulaire. Remarque: This.visible == true n'est pas toujours vrai lorsqu'il est défini sur true, il n'est donc pas utilisé du tout à cette fin, sauf pour masquer un formulaire.

Voici un exemple complet sur la façon de commencer à exécuter votre code après l'événement de chargement de formulaire. Il est recommandé de ne pas lier inutilement la boucle de messages Paint afin de créer un événement qui commencera à exécuter votre code en dehors de cette boucle.

using System.Windows.Forms;

espace de noms 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

}

}

1
Jamie