Как выполнить код ПОСЛЕ загрузки формы? - PullRequest
113 голосов
/ 20 октября 2008

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

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

Ответы [ 7 ]

169 голосов
/ 20 октября 2008

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

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

44 голосов
/ 20 октября 2008

я иногда использую (в Load)

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

или

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

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

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

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

Методы 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

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

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

6 голосов
/ 20 сентября 2015

Первый раз НЕ БУДЕТ запускаться "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.
}
6 голосов
/ 30 сентября 2013

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

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

Form MessageForm = new Form();
MessageForm.Shown += (s, e1) => { 
    Thread t = new Thread(() => Thread.Sleep(1500)); 
    t.Start(); 
    t.Join(); 
    MessageForm.Close(); 
};
2 голосов
/ 20 октября 2008

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

1 голос
/ 09 марта 2018

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

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

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

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

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

}

}

0 голосов
/ 08 мая 2015

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

// YourForm.ActiveForm.Close ();

    LoadingForm.ActiveForm.Close();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...