it-swarm.com.ru

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

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

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

113
adeel825

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

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

170
Matthias Schippling

Я иногда использую (в 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

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

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

44
Marc Gravell

Первый раз НЕ БУДЕТ запускать "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
Ahmed Sabry

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

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

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

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

2
Mitchel Sellers

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

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

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

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

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

}

}

1
Jamie