【问题标题】:How do I show a "Loading . . . please wait" message in Winforms for a long loading form?如何在 Winforms 中显示“正在加载...请稍候”消息以获取长加载表单?
【发布时间】:2010-12-27 10:50:14
【问题描述】:

我有一个非常慢的表单,因为表单上放置了许多控件。

因此,表单需要很长时间才能加载。

如何先加载表单,然后显示它,并在加载延迟时显示另一个表单,其中包含“正在加载...请稍候。”之类的消息?

【问题讨论】:

    标签: c# .net winforms .net-core


    【解决方案1】:

    使用单独的线程来显示一个简单的请稍候消息是矫枉过正的,尤其是如果您对线程没有太多经验。

    一个更简单的方法是创建一个“请稍候”表单并将其显示为一个无模式窗口,就在缓慢加载表单之前。主表单加载完成后,隐藏请等待表单。

    通过这种方式,您只使用一个主 UI 线程首先显示请等待表单,然后加载您的主表单。

    这种方法的唯一限制是您的“请稍候”表单无法动画(例如动画 GIF),因为线程正忙于加载您的主表单。

    PleaseWaitForm pleaseWait=new PleaseWaitForm ();
    
    // Display form modelessly
    pleaseWait.Show();
    
    //  ALlow main UI thread to properly display please wait form.
    Application.DoEvents();
    
    // Show or load the main form.
    mainForm.ShowDialog();
    

    【讨论】:

    • 在您的静态动画方法中使用动画图像的现有方法?
    • @Sadegh,您需要在您的请等待表单上使用一个控件,该控件在内部创建一个线程来为图像设置动画。我认为标准的 PictureBox 不会这样做。但是,如果您确实需要动画,那么 David 的一些链接页面值得一看。
    • 永远不要使用Application.DoEvents();!
    • @C Sharper,您的评论一定被截断了,并且“不恰当”这个词从最后丢失了。
    • 从来没有想过这样做,为我节省了很多时间。完美运行。谢谢!
    【解决方案2】:

    我查看了大多数发布的解决方案,但发现了一个我更喜欢的不同解决方案。它很简单,不使用线程,并且可以满足我的需求。

    http://weblogs.asp.net/kennykerr/archive/2004/11/26/where-is-form-s-loaded-event.aspx

    我在文章中添加了解决方案,并将代码移到了我的所有表单都继承自的基类中。现在我只调用一个函数:在表单加载时需要等待对话框的任何表单的 frm_load() 事件期间的 ShowWaitForm()。代码如下:

    public class MyFormBase : System.Windows.Forms.Form
    {
        private MyWaitForm _waitForm;
    
        protected void ShowWaitForm(string message)
        {
            // don't display more than one wait form at a time
            if (_waitForm != null && !_waitForm.IsDisposed) 
            {
                return;
            }
    
            _waitForm = new MyWaitForm();
            _waitForm.SetMessage(message); // "Loading data. Please wait..."
            _waitForm.TopMost = true;
            _waitForm.StartPosition = FormStartPosition.CenterScreen;
            _waitForm.Show();
            _waitForm.Refresh();
    
            // force the wait window to display for at least 700ms so it doesn't just flash on the screen
            System.Threading.Thread.Sleep(700);         
            Application.Idle += OnLoaded;
        }
    
        private void OnLoaded(object sender, EventArgs e)
        {
            Application.Idle -= OnLoaded;
            _waitForm.Close();
        }
    }
    

    MyWaitForm 是您创建的看起来像等待对话的表单的名称。我添加了一个 SetMessage() 函数来自定义等待表单上的文本。

    【讨论】:

    • 它说 mywaitform 不存在
    • 我发现这是一种最佳方法,我设计了自己的等待表单,它运行良好..
    • 这是一个在等待表单打开时在屏幕上放置静态图像或文本的好主意。我将调用更改为 ShowWaitForm 并将其放在基类中。然后我在基类中添加了一个布尔属性,这样我就可以设置该属性并加载等待表单。很棒的解决方案!
    【解决方案3】:

    您想查看“启动”屏幕。

    显示另一个“Splash”表单并等待处理完成。

    这里有一个example 说明如何操作。

    【讨论】:

    • 嗨大卫,链接给出了 404
    【解决方案4】:

    一个简单的解决方案:

    using (Form2 f2 = new Form2())
    {
        f2.Show();
        f2.Update();
    
        System.Threading.Thread.Sleep(2500);
    } // f2 is closed and disposed here
    

    然后用 Loading 代替 Sleep。
    这会故意阻塞 UI 线程。

    【讨论】:

    • 我喜欢这个简单的解决方案。是的,它不适用于动画 gif,但我刚刚在对话框上拍了一张沙漏的图像,很高兴。
    【解决方案5】:

    另一种使“加载屏幕”仅在特定时间显示的方法是将其放在事件之前并在事件完成后将其关闭。

    例如:您想显示一个将结果保存为MS Excel文件的事件的加载表单并在处理完成后将其关闭,请执行以下操作:

    LoadingWindow loadingWindow = new LoadingWindow();
    
    try
    {
        loadingWindow.Show();                
        this.exportToExcelfile();
        loadingWindow.Close();
    }
    catch (Exception ex)
    {
        MessageBox.Show("Exception EXPORT: " + ex.Message);
    }
    

    或者您可以将loadingWindow.Close() 放在finally 块内。

    【讨论】:

    • 这几乎永远不会奏效。前台线程继续 exportToExcelFile,在 loadingWindow 显示之前它很忙。
    【解决方案6】:

    您应该创建一个后台线程来创建和填充表单。这将允许您的前台线程显示加载消息。

    【讨论】:

      【解决方案7】:

      你可以看看我的启动画面实现: C# winforms startup (Splash) form not hiding

      【讨论】:

        【解决方案8】:

        我将一些动画 gif 放入一个名为 FormWait 的表单中,然后我将其命名为:

        // show the form
        new Thread(() => new FormWait().ShowDialog()).Start();
        
        // do the heavy stuff here
        
        // get the form reference back and close it
        FormWait f = new FormWait();
        f = (FormWait)Application.OpenForms["FormWait"];
        f.Close();
        

        【讨论】:

        • 我尝试使用它,但我得到一个 IO 非法线程交叉异常。我通过使其“线程安全”对其进行了修改。不是最佳实践,但对于简单的等待形式,它是可以接受的:将 f.Close() 替换为 f.Invoke(new ThreadStart(delegate {f.Close();}));
        • 我在这里添加了一个经过测试的解决方案:stackoverflow.com/questions/15769276/…
        【解决方案9】:

        嗯,我是这样做的。

                NormalWaitDialog/*your wait form*/ _frmWaitDialog = null;
        
        
                //Btn Load Click Event
                _frmWaitDialog = new NormalWaitDialog();
                _frmWaitDialog.Shown += async (s, ee) =>
                {
                    await Task.Run(() =>
                   {
                       // DO YOUR STUFF HERE 
        
                       //Made long running loop to imitate lengthy process
                       int x = 0;
                       for (int i = 0; i < int.MaxValue; i++)
                       {
                           x += i;
                       }
        
                   }).ConfigureAwait(true);
                    _frmWaitDialog.Close();
                };
                _frmWaitDialog.ShowDialog(this);
        

        【讨论】:

        • 我尝试过这样的事情,但是当我从资源管理器中的链接文件类型打开它时,它会导致我的应用失去焦点...
        • .ConfigureAwait(true) 是默认值
        【解决方案10】:

        当您还拥有动画图像时,最好的方法是:

        1- 您必须创建一个“WaitForm”来接收它将在后台执行的方法。喜欢这个

        public partial class WaitForm : Form
        {
            private readonly MethodInvoker method;
        
            public WaitForm(MethodInvoker action)
            {
                InitializeComponent();
                method = action;
            }
        
            private void WaitForm_Load(object sender, EventArgs e)
            {
                new Thread(() =>
                {
                    method.Invoke();
                    InvokeAction(this, Dispose);
                }).Start();
            }
        
            public static void InvokeAction(Control control, MethodInvoker action)
            {
                if (control.InvokeRequired)
                {
                    control.BeginInvoke(action);
                }
                else
                {
                    action();
                }
            }
        }
        

        2 - 你可以像这样使用Waitform

        private void btnShowWait_Click(object sender, EventArgs e)
        {
            new WaitForm(() => /*Simulate long task*/ Thread.Sleep(2000)).ShowDialog();
        }
        

        【讨论】:

        • 像魅力一样工作。谢谢! +1
        【解决方案11】:

        或者如果您不想要动画等花哨的东西。您可以创建一个标签并将其停靠在窗体上,然后将其 z-index 从文档大纲窗口更改为 0 并为其设置背景色,以便其他控件不可见比在表单加载事件中运行一次Application.DoEvents() 并在表单显示事件中进行所有编码,并在显示事件的 and 中将标签可见属性设置为 false,然后再次运行 Application.DoEvents()

        【讨论】:

          【解决方案12】:

          我知道已经晚了,但我喜欢这个项目,我想和你分享,它非常有用和样本 Simple Display Dialog of Waiting in WinForms

          【讨论】:

            猜你喜欢
            • 2015-01-17
            • 1970-01-01
            • 1970-01-01
            • 2010-11-08
            • 1970-01-01
            • 1970-01-01
            • 2021-06-21
            • 1970-01-01
            • 2012-09-12
            相关资源
            最近更新 更多