Как выполнить код ПОСЛЕ загрузки формы?


126

В .NET у Windows Forms есть событие, которое запускается до загрузки формы (Form.Load), но нет соответствующего события, которое запускается ПОСЛЕ загрузки формы. Я хотел бы выполнить некоторую логику после загрузки формы.

Кто-нибудь может посоветовать решение?


Хотя на этот вопрос есть очень хорошие ответы, возможно, стоит упомянуть об этом: docs.microsoft.com/en-us/dotnet/framework/winforms/…
Ришав

Ответы:


192

Вы можете использовать событие «Показано»: MSDN - Form.Shown

«Событие Shown возникает только при первом отображении формы; впоследствии сворачивание, развертывание, восстановление, скрытие, отображение или аннулирование и перерисовка не вызовут это событие».


10
Мне кажется, что показанный обработчик выполняется ВО ВРЕМЯ загрузки формы ... я ошибаюсь?
ckonig

3
Старый, но золотой ... Да, вы ошибаетесь. Графический интерфейс не может запускать параллельные задачи, важно что-то делать, пока выполняется другое выполнение.
Dennis Ziolkowski

2
Если в обработчике событий Load есть код, вызывающий Application.DoEvents (), событие Shown запускается до того, как обработчики событий Load завершат свое выполнение. Это связано с тем, что событие Shown фактически помещается в очередь сообщений с помощью Form.BeginInvoke (ShownEvent), а DoEvents () заставляет его срабатывать до завершения загрузки.
Artemix

1
Мне было мало не работать на C #. Мне пришлось добавить, Shown += Form1_Shown;как было предложено в другой ветке
ocramot

11
вам следует добавить This.Refresh (); внутри события Shown, прежде чем ваша логика, и оно будет удерживать и обновлять форму до полной загрузки, прежде чем ваша логика начнет работать,
Айлиан Краспа,

49

Иногда использую (в нагрузке)

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

или

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

(замените "this" на свою переменную формы, если вы обрабатываете событие в экземпляре, отличном от "this").

Это помещает вызов в цикл окон-форм, поэтому он обрабатывается, когда форма обрабатывает очередь сообщений.

[обновлено по запросу]

Методы Control.Invoke / Control.BeginInvoke предназначены для использования с потоками и являются механизмом для передачи работы в поток пользовательского интерфейса. Обычно это используется рабочими потоками и т. Д. Control.Invoke выполняет синхронный вызов, тогда как Control.BeginInvoke выполняет асинхронный вызов.

Обычно они используются как:

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

Он делает это, помещая сообщение в очередь сообщений Windows; поток пользовательского интерфейса (в какой-то момент) удаляет сообщение из очереди, обрабатывает делегата и сигнализирует рабочему о завершении ... пока все хорошо ;-p

ХОРОШО; Итак, что произойдет, если мы используем Control.Invoke / Control.BeginInvoke в потоке пользовательского интерфейса? Он справляется ... если вы вызываете Control.Invoke, достаточно разумно знать, что блокировка очереди сообщений вызовет немедленную взаимоблокировку - поэтому, если вы уже находитесь в потоке пользовательского интерфейса, он просто немедленно запускает код ... так что нам не помогает ...

Но Control.BeginInvoke работает иначе: он всегда помещает работу в очередь, даже если мы уже находимся в потоке пользовательского интерфейса. Это действительно простой способ сказать «через мгновение», но без неудобств, связанных с таймерами и т. Д. (Которые в любом случае должны будут сделать то же самое!).


1
Не совсем понял это. Не могли бы вы объяснить немного больше?
Торбьёрн

Привет, Марк, можно ли сделать форму отзывчивой, пока процесс завершен, который вызывается в BeginInvoke ??
huMpty duMpty

что это эквивалентно в WPF?
мт

6

В первый раз он НЕ БУДЕТ запускать «AfterLoading»,
он просто зарегистрирует его для запуска СЛЕДУЮЩЕЙ загрузки.

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

У меня была такая же проблема, и я решил ее следующим образом:

На самом деле я хочу показать сообщение и автоматически закрыть его через 2 секунды. Для этого мне пришлось сгенерировать (динамически) простую форму и одну метку, показывающую сообщение, остановить сообщение на 1500 мс, чтобы пользователь прочитал его. И закройте динамически созданную форму. Показанное событие происходит после события загрузки. Итак, код

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

2

Вы также можете попробовать поместить свой код в событие Activated формы, если хотите, чтобы это произошло, как раз тогда, когда форма активирована. Вам нужно будет ввести логическую проверку «выполнено», если она должна запускаться только при первой активации.


1

Это старый вопрос, и он больше зависит от того, когда вам нужно начинать рутину. Поскольку никому не нужно исключение нулевой ссылки, всегда лучше сначала проверить наличие null, а затем использовать по мере необходимости; одно это может избавить вас от многих неприятностей.

Наиболее распространенная причина этого типа вопросов - когда контейнер или тип настраиваемого элемента управления пытается получить доступ к свойствам, инициализированным за пределами настраиваемого класса, где эти свойства еще не инициализированы, что потенциально может привести к заполнению нулевых значений и даже может вызвать исключения из нулевой ссылки по типам объектов. Это означает, что ваш класс запущен до того, как он будет полностью инициализирован - до того, как вы закончите настройку своих свойств и т. Д. Другая возможная причина такого типа вопросов - когда выполнять пользовательскую графику.

Чтобы лучше всего ответить на вопрос о том, когда начинать выполнение кода после события загрузки формы, нужно отслеживать сообщение WM_Paint или подключаться непосредственно к самому событию рисования. Зачем? Событие рисования срабатывает только тогда, когда все модули полностью загружены относительно события загрузки формы. Примечание. This.visible == true не всегда является истинным, если для него установлено значение true, поэтому он вообще не используется для этой цели, кроме как для скрытия формы.

Ниже приведен полный пример того, как начать выполнение кода после события загрузки формы. Рекомендуется без надобности не связывать цикл сообщений рисования, поэтому мы создадим событие, которое начнет выполнение вашего кода вне этого цикла.

using System.Windows.Forms;

пространство имен 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

}

}


Это кажется невероятно многословным, и есть ли у него какие-то преимущества перед простой ловлей события «Показано»?
Стив Смит

0

Я знаю, что это старый пост. Но вот как я это сделал:

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

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

-9

Вы можете закрыть свою форму после некоторого выполнения ..

//YourForm.ActiveForm.Close ();

    LoadingForm.ActiveForm.Close();
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.