【问题标题】:How do I execute code AFTER a form has loaded?表单加载后如何执行代码?
【发布时间】:2010-09-18 03:19:01
【问题描述】:

在 .NET 中,Windows 窗体有一个在窗体加载之前触发的事件 (Form.Load),但在窗体加载之后没有相应的事件触发。我想在表单加载后执行一些逻辑。

谁能提供解决方案的建议?

【问题讨论】:

标签: c# .net winforms events


【解决方案1】:

您可以使用“显示”事件:MSDN - Form.Shown

“Shown 事件仅在第一次显示表单时引发;随后最小化、最大化、恢复、隐藏、显示或无效化和重新绘制不会引发此事件。”

【讨论】:

  • 对我来说,显示的处理程序似乎是在表单加载时执行的......我错了吗?
  • 旧但黄金...是的,你错了。 GUI 无法运行并行任务,重要的是在另一次执行完成时做某事。
  • 如果在 Load 事件处理程序中有调用 Application.DoEvents() 的代码,则 Shown 事件会在 Load 事件处理程序完成执行之前触发。这是因为 Shown 事件实际上是使用 Form.BeginInvoke(ShownEvent) 和 DoEvents() 强制它在 Load 完成之前触发的。
  • 在 C# 中对我来说还不够。我必须按照another thread中的建议添加Shown += Form1_Shown;
  • 你应该添加 This.Refresh();在您的逻辑之前的 Shown 事件中,它将在您的逻辑开始运行之前保持并刷新表单以完全加载
【解决方案2】:

我有时使用(在加载中)

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

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

(如果您正在处理“this”以外的实例上的事件,请将“this”更改为您的表单变量)。

这会将调用推送到 windows-forms 循环中,因此它会在表单处理消息队列时得到处理。

[应要求更新]

Control.Invoke/Control.BeginInvoke 方法旨在与线程一起使用,并且是一种将工作推送到 UI 线程的机制。通常这由工作线程等使用。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 消息队列中来做到这一点; UI 线程(在某些时候)使消息出队,处理委托,并向工作人员发出它已完成的信号……到目前为止一切顺利;-p

好的;那么如果我们在 UI 线程上使用 Control.Invoke / Control.BeginInvoke 会发生什么?它可以应付...如果您调用 Control.Invoke,那么很明智地知道消息队列上的阻塞会导致立即死锁-因此,如果您已经在 UI 线程上,它只会立即运行代码...这样对我们没有帮助...

但 Control.BeginInvoke 的工作方式不同:它总是将工作推送到队列中,即使我们已经在 UI 线程上。这是一种非常简单的说“一会儿”的方式,但没有计时器等带来的不便(无论如何,它仍然必须做同样的事情!)。

【讨论】:

  • 没完全看懂那个。你能再解释一下吗?
  • 嗨,马克,是否可以在 BeginInvoke 中调用的过程完成时使表单响应??
  • WPF 中的等价物是什么?
  • 最佳答案在这里
【解决方案3】:

第一次它不会启动“AfterLoading”,
它只会注册它以启动 NEXT Load。

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

【讨论】:

    【解决方案4】:

    我遇到了同样的问题,解决方法如下:

    实际上我想显示消息并在 2 秒后自动关闭它。为此,我必须生成(动态)简单的表单和一个显示消息的标签,停止消息 1500 毫秒,以便用户阅读它。并关闭动态创建的表单。显示的事件发生在加载事件之后。所以代码是

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

    【讨论】:

      【解决方案5】:

      如果您希望它在表单被激活时发生,您也可以尝试将代码放入表单的 Activated 事件中。您需要输入一个布尔值“已执行”检查,但它是否应该只在第一次激活时运行。

      【讨论】:

        【解决方案6】:

        这是一个老问题,更多地取决于您何时需要开始您的例程。由于没有人想要空引用异常,因此最好先检查空值,然后根据需要使用;仅此一项就可以为您节省很多痛苦。

        此类问题的最常见原因是,当容器或自定义控件类型尝试访问在自定义类之外初始化的属性时,这些属性尚未初始化,从而可能导致填充空值,甚至可能导致对象类型的空引用异常。这意味着您的类在完全初始化之前正在运行 - 在您完成设置属性等之前。此类问题的另一个可能原因是何时执行自定义图形。

        为了最好地回答表单加载事件之后何时开始执行代码的问题是监视 WM_Paint 消息或直接挂钩到绘制事件本身。为什么?只有当所有模块相对于表单加载事件都已完全加载时,才会触发绘制事件。注意: this.visible == true 在设置为 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
        
        }
        

        }

        【讨论】:

        • 这似乎非常冗长,与简单地捕捉 Shown 事件相比有什么优势吗?
        【解决方案7】:

        我知道这是一篇旧帖子。但这是我的做法:

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

        【讨论】:

          【解决方案8】:

          以下是在之前的正确答案中添加的一些细节,尤其是 Matthias Schappling 的答案。

          在 Form1_Load 中添加一个事件处理程序,如下所示:

            private void Form1_Load(object sender, EventArgs e)
            {
             this.Shown += new EventHandler(Form1_Shown);
            }
          

          接下来,添加将对代码执行某些操作的方法

            private void Form1_Shown(Object sender, EventArgs e)
            {
             draw_on_my_form_or_some_other_action();
            }
          

          【讨论】:

            【解决方案9】:

            您可以在执行一些操作后关闭您的表单..

            //YourForm.ActiveForm.Close();

                LoadingForm.ActiveForm.Close();
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2016-05-29
              相关资源
              最近更新 更多