Wie führe ich Code aus, nachdem ein Formular geladen wurde?


126

In .NET gibt es in Windows Forms ein Ereignis, das ausgelöst wird, bevor das Formular geladen wird (Form.Load). Es gibt jedoch kein entsprechendes Ereignis, das nach dem Laden des Formulars ausgelöst wird. Ich möchte eine Logik ausführen, nachdem das Formular geladen wurde.

Kann jemand eine Lösung empfehlen?


Obwohl diese Frage sehr gute Antworten hat, könnte es erwähnenswert sein, dies zu erwähnen: docs.microsoft.com/en-us/dotnet/framework/winforms/…
Rishav

Antworten:


192

Sie können das Ereignis "Angezeigt" verwenden: MSDN - Form.Shown

"Das angezeigte Ereignis wird nur beim ersten Anzeigen eines Formulars ausgelöst. Durch anschließendes Minimieren, Maximieren, Wiederherstellen, Ausblenden, Anzeigen oder Ungültigmachen und Neulackieren wird dieses Ereignis nicht ausgelöst."


10
Mir scheint, dass der angezeigte Handler ausgeführt wird, während das Formular geladen wird ... irre ich mich?
König

3
Alt aber gold ... Ja, du liegst falsch. GUI kann keine parallelen Aufgaben ausführen, was wichtig ist, um etwas zu tun, während eine andere Ausführung durchgeführt wird.
Dennis Ziolkowski

2
Wenn im Load-Ereignishandler ein Code vorhanden ist, der Application.DoEvents () aufruft, wird das angezeigte Ereignis ausgelöst, bevor die Load-Ereignishandler ihre Ausführung beendet haben. Dies liegt daran, dass das angezeigte Ereignis mithilfe von Form.BeginInvoke (ShownEvent) und DoEvents () tatsächlich in eine Nachrichtenwarteschlange gestellt wird, damit es ausgelöst wird, bevor das Laden abgeschlossen ist.
Artemix

1
Es war nicht genug, nicht für mich zu arbeiten, in C #. Ich musste hinzufügen, Shown += Form1_Shown;wie in einem anderen Thread vorgeschlagen
Ocramot

11
Sie sollten This.Refresh () hinzufügen; innerhalb des angezeigten Ereignisses zuerst vor Ihrer Logik und es wird das Formular halten und
aktualisieren,

49

Ich benutze manchmal (in Load)

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

oder

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

(Ändern Sie "this" in Ihre Formularvariable, wenn Sie das Ereignis auf einer anderen Instanz als "this" behandeln.)

Dadurch wird der Aufruf in die Windows-Forms-Schleife verschoben, sodass er verarbeitet wird, wenn das Formular die Nachrichtenwarteschlange verarbeitet.

[auf Anfrage aktualisiert]

Die Control.Invoke / Control.BeginInvoke-Methoden sind für die Verwendung mit Threading vorgesehen und stellen einen Mechanismus dar, mit dem die Arbeit auf den UI-Thread übertragen werden kann. Normalerweise wird dies von Arbeitsthreads usw. verwendet. Control.Invoke führt einen synchronen Aufruf aus, während Control.BeginInvoke einen asynchronen Aufruf ausführt.

Normalerweise werden diese verwendet als:

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

Dazu wird eine Nachricht in die Windows-Nachrichtenwarteschlange verschoben. Der UI-Thread stellt die Nachricht (irgendwann) aus der Warteschlange, verarbeitet den Delegaten und signalisiert dem Worker, dass er abgeschlossen wurde ... soweit so gut ;-p

OK; Was passiert also, wenn wir Control.Invoke / Control.BeginInvoke für den UI-Thread verwenden? Es kommt zurecht ... wenn Sie Control.Invoke aufrufen, ist es vernünftig zu wissen, dass das Blockieren der Nachrichtenwarteschlange einen sofortigen Deadlock verursachen würde. Wenn Sie sich also bereits im UI-Thread befinden, wird der Code einfach sofort ausgeführt ... damit hilft uns nicht ...

Aber Control.BeginInvoke funktioniert anders: Es schiebt immer Arbeit in die Warteschlange, auch wenn wir uns bereits im UI-Thread befinden. Dies ist eine wirklich einfache Art, "in einem Moment" zu sagen, aber ohne die Unannehmlichkeiten von Timern usw. (die sowieso immer noch das Gleiche tun müssten!).


1
Habe das nicht ganz verstanden. Können Sie uns etwas mehr erklären?
Torbjørn

Hallo zusammen, ist es möglich, das Formular ansprechbar zu machen, während der in BeginInvoke aufgerufene Prozess abgeschlossen ist?
huMpty duMpty

Was ist das Äquivalent in WPF?
Mrid

6

Beim ersten Start wird "AfterLoading" NICHT gestartet, sondern
nur registriert, um das nächste Laden zu starten.

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

Ich hatte das gleiche Problem und löste es wie folgt:

Eigentlich möchte ich Nachricht anzeigen und sie nach 2 Sekunden automatisch schließen. Dafür musste ich ein (dynamisch) einfaches Formular und ein Etikett mit der Nachricht erstellen. Die Nachricht für 1500 ms anhalten, damit der Benutzer sie lesen kann. Und Schließen Sie das dynamisch erstellte Formular. Das angezeigte Ereignis tritt nach dem Ladeereignis auf. Code ist also

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

2

Sie können auch versuchen, Ihren Code in das aktivierte Ereignis des Formulars einzufügen, wenn Sie möchten, dass es auftritt, sobald das Formular aktiviert ist. Sie müssten jedoch eine boolesche Prüfung "hat ausgeführt" durchführen, wenn diese nur bei der ersten Aktivierung ausgeführt werden soll.


1

Dies ist eine alte Frage und hängt mehr davon ab, wann Sie Ihre Routinen starten müssen. Da niemand eine Nullreferenzausnahme wünscht, ist es immer am besten, zuerst nach Null zu suchen und sie dann nach Bedarf zu verwenden. das allein kann dir viel Kummer ersparen.

Der häufigste Grund für diesen Fragetyp ist, wenn ein Container oder ein benutzerdefinierter Steuerelementtyp versucht, auf Eigenschaften zuzugreifen, die außerhalb einer benutzerdefinierten Klasse initialisiert wurden, in der diese Eigenschaften noch nicht initialisiert wurden. Dies kann möglicherweise dazu führen, dass Nullwerte ausgefüllt werden, und kann sogar Nullreferenzausnahmen verursachen auf Objekttypen. Dies bedeutet, dass Ihre Klasse ausgeführt wird, bevor sie vollständig initialisiert ist - bevor Sie Ihre Eigenschaften usw. festgelegt haben. Ein weiterer möglicher Grund für diese Art von Frage ist, wann benutzerdefinierte Grafiken ausgeführt werden müssen.

Um die Frage zu beantworten, wann nach dem Laden des Formulars mit der Ausführung von Code begonnen werden soll, müssen Sie die WM_Paint-Nachricht überwachen oder sich direkt an das Paint-Ereignis selbst anschließen. Warum? Das Malereignis wird nur ausgelöst, wenn alle Module in Bezug auf Ihr Formularladeereignis vollständig geladen wurden. Hinweis: This.visible == true ist nicht immer true, wenn es auf true gesetzt ist. Daher wird es für diesen Zweck überhaupt nicht verwendet, außer um ein Formular auszublenden.

Im Folgenden finden Sie ein vollständiges Beispiel dafür, wie Sie nach dem Laden des Formulars mit der Ausführung Ihres Codes beginnen. Es wird empfohlen, die Paint-Message-Schleife nicht unnötig zu binden, damit ein Ereignis erstellt wird, mit dem Ihr Code außerhalb dieser Schleife ausgeführt wird.

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

}

}}


Dies scheint unglaublich langwierig zu sein, und hat es irgendwelche Vorteile gegenüber dem einfachen Abfangen des gezeigten Ereignisses?
Steve Smith

0

Ich weiß, dass dies ein alter Beitrag ist. Aber so habe ich es gemacht:

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

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

-9

Sie können Ihr Formular nach einiger Ausführung schließen.

//YourForm.ActiveForm.Close ();

    LoadingForm.ActiveForm.Close();
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.