Jak wykonać kod PO załadowaniu formularza?


126

W .NET formularze systemu Windows mają zdarzenie, które jest wyzwalane przed załadowaniem formularza (Form.Load), ale nie ma odpowiedniego zdarzenia, które jest wyzwalane PO załadowaniu formularza. Chciałbym wykonać jakąś logikę po załadowaniu formularza.

Czy ktoś może doradzić rozwiązanie?


Chociaż na to pytanie można znaleźć bardzo dobre odpowiedzi, warto wspomnieć o tym: docs.microsoft.com/en-us/dotnet/framework/winforms/…
Rishav

Odpowiedzi:


192

Możesz użyć zdarzenia „Shown”: MSDN - Form.Shown

„Zdarzenie Shown jest wywoływane tylko przy pierwszym wyświetleniu formularza; późniejsze zminimalizowanie, maksymalizacja, przywrócenie, ukrycie, pokazanie lub unieważnienie i ponowne malowanie nie spowoduje podniesienia tego zdarzenia”.


10
Wydaje mi się, że pokazany program obsługi jest wykonywany PODCZAS ładowania formularza ... czy się mylę?
ckonig

3
Stare, ale złote ... Tak, mylisz się. GUI nie może uruchamiać równoległych zadań, co jest ważne, aby coś zrobić PODCZAS innego wykonania.
Dennis Ziolkowski

2
Jeśli w module obsługi zdarzeń Load istnieje kod, który wywołuje Application.DoEvents (), zdarzenie Shown jest wyzwalane przed zakończeniem wykonywania przez programy obsługi zdarzeń Load. Dzieje się tak, ponieważ zdarzenie Shown jest w rzeczywistości umieszczane w kolejce komunikatów przy użyciu Form.BeginInvoke (ShownEvent) i DoEvents () wymusza jego uruchomienie przed zakończeniem ładowania.
Artemix

1
Dla mnie to nie wystarczyło, w C #. Musiałem dodać Shown += Form1_Shown;zgodnie z sugestią w innym wątku
ocramot

11
należy dodać This.Refresh (); wewnątrz przedstawionym przypadku zanim logika i będzie trzymać i odświeżyć formularza, aby w pełni załadowany przed logiki zaczynają biec
Aylian Craspa

49

Czasami używam (w Load)

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

lub

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

(zmień „this” na swoją zmienną formularza, jeśli obsługujesz zdarzenie w instancji innej niż „this”).

To wypycha wywołanie do pętli Windows-Forms, więc jest przetwarzane, gdy formularz przetwarza kolejkę komunikatów.

[aktualizowane na żądanie]

Metody Control.Invoke / Control.BeginInvoke są przeznaczone do użytku z wątkami i są mechanizmem wypychania pracy do wątku interfejsu użytkownika. Zwykle jest to używane przez wątki robocze itp. Control.Invoke wykonuje wywołanie synchroniczne, podczas gdy Control.BeginInvoke wykonuje wywołanie asynchroniczne.

Zwykle byłyby używane jako:

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

Robi to poprzez wypychanie wiadomości do kolejki wiadomości systemu Windows; Wątek interfejsu użytkownika (w pewnym momencie) usuwa z kolejki wiadomość, przetwarza delegata i sygnalizuje pracownikowi, że zakończył pracę ... na razie tak dobrze ;-p

DOBRZE; więc co się stanie, jeśli użyjemy Control.Invoke / Control.BeginInvoke w wątku interfejsu użytkownika? Radzi sobie ... jeśli wywołasz Control.Invoke, rozsądnie jest wiedzieć, że blokowanie kolejki komunikatów spowodowałoby natychmiastowy zakleszczenie - więc jeśli jesteś już w wątku interfejsu użytkownika, po prostu natychmiast uruchamia kod ... więc nam nie pomaga ...

Ale Control.BeginInvoke działa inaczej: zawsze wypycha pracę do kolejki, nawet jeśli jesteśmy już w wątku interfejsu użytkownika. To naprawdę prosty sposób na powiedzenie „za chwilę”, ale bez niedogodności związanych z licznikami czasu itp. (Które i tak musiałyby robić to samo!).


1
Nie do końca to rozumiałem. Czy możesz wyjaśnić trochę więcej?
Torbjørn

Cześć, mark, czy jest możliwe, aby formularz był responsywny, podczas gdy proces jest wywoływany w BeginInvoke?
huMpty duMpty

co to jest odpowiednik w WPF?
środa

6

Za pierwszym razem NIE BĘDZIE uruchomił „AfterLoading”,
po prostu zarejestruje go, aby rozpocząć NEXT Loading .

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

Miałem ten sam problem i rozwiązałem go w następujący sposób:

Właściwie chcę pokazać wiadomość i zamknąć ją automatycznie po 2 sekundach. W tym celu musiałem wygenerować (dynamicznie) prosty formularz i jedną etykietę pokazującą wiadomość, zatrzymaj wiadomość na 1500 ms, aby użytkownik ją przeczytał. I Zamknij dynamicznie tworzoną formę. Pokazane zdarzenie występuje po zdarzeniu ładowania. Więc kod jest

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

2

Możesz również spróbować umieścić swój kod w zdarzeniu Activated formularza, jeśli chcesz, aby to nastąpiło, gdy formularz jest aktywowany. Musiałbyś jednak ustawić boolean "wykonał" sprawdzenie, jeśli ma on działać tylko przy pierwszej aktywacji.


1

To stare pytanie i zależy bardziej od tego, kiedy musisz rozpocząć swoje procedury. Ponieważ nikt nie chce zerowego wyjątku odniesienia, zawsze najlepiej jest najpierw sprawdzić wartość null, a następnie użyć w razie potrzeby; Samo to może zaoszczędzić wiele smutku.

Najczęstszą przyczyną tego typu pytań jest sytuacja, gdy kontener lub niestandardowy typ kontrolny próbuje uzyskać dostęp do właściwości zainicjowanych poza klasą niestandardową, w której te właściwości nie zostały jeszcze zainicjowane, co może spowodować wypełnienie wartości null, a nawet spowodować wyjątki odwołań o wartości null na typach obiektów. Oznacza to, że Twoja klasa jest uruchomiona, zanim zostanie w pełni zainicjowana - przed zakończeniem ustawiania właściwości itp. Innym możliwym powodem tego typu pytań jest to, kiedy wykonać niestandardową grafikę.

Najlepszą odpowiedzią na pytanie, kiedy rozpocząć wykonywanie kodu po zdarzeniu ładowania formularza, jest monitorowanie wiadomości WM_Paint lub przechodzenie bezpośrednio do samego zdarzenia malowania. Czemu? Zdarzenie malowania jest uruchamiane tylko wtedy, gdy wszystkie moduły zostaną w pełni załadowane w odniesieniu do zdarzenia ładowania formularza. Uwaga: This.visible == true nie zawsze jest prawdziwe, gdy jest ustawione na true, więc nie jest w ogóle używane do tego celu, z wyjątkiem ukrycia formularza.

Poniżej znajduje się pełny przykład, jak rozpocząć wykonywanie kodu po zdarzeniu ładowania formularza. Zaleca się, aby nie wiązać niepotrzebnie pętli komunikatów malowania, abyśmy utworzyli zdarzenie, które rozpocznie wykonywanie kodu poza tą pętlą.

using System.Windows.Forms;

przestrzeń nazw 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

}

}


Wydaje się to niezwykle rozwlekłe i czy ma jakieś zalety w porównaniu do zwykłego łapania pokazu?
Steve Smith

0

Wiem, że to stary post. Ale oto jak to zrobiłem:

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

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

-9

Możesz zamknąć formularz po pewnym wykonaniu.

//YourForm.ActiveForm.Close ();

    LoadingForm.ActiveForm.Close();
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.