Как выполнить код после загрузки формы?


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

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

7 106

7 ответов:

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

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

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

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

или

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

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

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

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

Управление.Вызов/Управление.Методы BeginInvoke предназначены для использования с потоковой обработкой и представляют собой механизм для выталкивания работа в потоке пользовательского интерфейса. Обычно это используется рабочими потоками и т. д. Управление.Invoke выполняет синхронный вызов, где-как элемент управления.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

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

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

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

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

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

первый раз он не будет запускаться "после загрузки",
Он просто зарегистрирует его, чтобы начать следующую загрузку.

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.
}

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

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

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

чтобы лучше ответить на вопрос о том, когда начать выполнение кода после события загрузки формы, необходимо отслеживать сообщение WM_Paint или подключаться непосредственно к самому событию paint. Зачем? Краска событие срабатывает только тогда, когда все модули полностью загружены относительно вашего события загрузки формы. отметить это.visible = = 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

}

}

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

//YourForm.ActiveForm.Закрыть();

    LoadingForm.ActiveForm.Close();