C# Winforms:如何显示一个";“装载”;形式?

C# Winforms:如何显示一个";“装载”;形式?,c#,winforms,C#,Winforms,我有一个网格,当双击一行时,就会加载一个表单。但是,必须加载大量数据,因此我想显示一个简单的表单,其中包含文本“loading,please wait…”。当所有加载完成时,表单必须消失 这就是我现在拥有的,但它不起作用: 调用包含大量数据的表单的代码: FormWithLotData form = new FormWithLotData(); form.ShowDialog(this); FormWithLotData的构造函数: // Show load form FormIsLoadin

我有一个网格,当双击一行时,就会加载一个表单。但是,必须加载大量数据,因此我想显示一个简单的表单,其中包含文本“loading,please wait…”。当所有加载完成时,表单必须消失

这就是我现在拥有的,但它不起作用:

调用包含大量数据的表单的代码:

FormWithLotData form = new FormWithLotData();
form.ShowDialog(this);
FormWithLotData的构造函数:

// Show load form
FormIsLoading frm = new FormIsLoading();
_CloseLoadForm closeForm = new _CloseLoadForm(frm.Close);
System.Threading.Thread thread = new System.Threading.Thread(frm.Show);

thread.Start();

InitializeComponent();

this.Visible = false;

LoadAllData();

this.Visible = true;

// Close load form
Invoke(closeForm);
希望你能帮助我

编辑: 我想在加载表单上显示动画gif

解决方案:
我已经创建了一个后台工作人员。DoWork事件处理所有加载,并通过使用invoke()方法将节点添加到treeview。现在,GUI没有挂起,用户也不知道应用程序正在挂起。

在Form\u Load事件中,添加以下内容:

this.Visible = true;
Application.DoEvents();
在进行任何其他处理之前。Application.DoEvents导致UI在当前状态下显示表单,在当前状态下,当您进行其他处理时,UI线程通常被锁定。

如何

FormIsLoading frm = new FormIsLoading();
frm.Show();
Application.DoEvents();

// ... load data ...

frm.Close();

您需要反转代码

FormWithLotData的构造函数正在UI线程中运行。这是必须显示FormsLoading窗体的线程。因此,与其尝试使用新线程显示此表单,不如使用它加载数据

其他人建议的DoEvents方法是最容易实现的,并且(可能?我自己从未做过)可能会很好地工作

更好的模式是在工作线程上加载数据。在显示FormWithLotData之前,开始在后台线程上加载数据,并显示加载对话框。加载数据的方法应该在加载对话框中有一个回调方法,以指示何时应该关闭()。一旦它关闭,您就可以构建一个新的FWLD,将已经加载的数据传递给它,并显示它

在调用表单后尝试加载数据会将UI与数据操作混为一谈,迫使表单不仅负责UI,还负责数据检索。不适合接吻和单一责任,伊姆霍


更新之后,DoEvents似乎将是您问题的唯一真实答案,但有一些警告


在构建树时,您将无法以模式显示另一个窗体。您仍然需要在表单的构造函数中完成繁重的工作。您仍然需要隐藏主窗体并显示()加载窗体(而不是ShowDialog)。在构建树时,您还必须在每一个可能的时刻调用DoEvents。这并不是一个完美的解决方案,但在这一点上,它可能是您最好的选择。

不要直接在UI线程中执行
LoadAllData()
,而是启动后台线程来执行。在表单加载的事件处理程序中,使用
AutoResetEvent
,等待后台数据检索线程发出信号。一旦发出信号,您就可以继续对数据执行任何需要执行的操作,比如将数据绑定到UI中

由于各种原因,此方法仍然有点笨拙,但它将帮助您开始

编辑:我对上面的答案很懒。。。更好的选择是将委托(回调)传递给后台线程,当调用委托(在完成数据检索后)时,委托会将自身封送回UI线程,并开始处理数据

  • 在表单中,可以使用计时器控件模拟加载 当ProgressBar达到100时,它将卸载窗体或任何 一种动画

    对于进度条形码,只需从工具箱中添加控件,然后 编写以下代码:


  • 我已经创建了一个加载事件,并将这段代码放入事件中。现在我得到了一个例外:
    Invoke或BeginInvoke不能在控件上调用,直到创建了窗口句柄。
    实际上,我想建议这样做。但是当您阻止等待ARE的UI线程时,您就是在阻止UI线程。因此,这使得整个后台工作变得毫无意义。您需要的是LoadAllData方法可以调用的回调,以向UI线程发出数据已加载的信号。它仍然可以工作,因为后台线程没有被阻塞,它是发出ARE信号的线程,这意味着UI线程可以继续。无论如何,我已经做了一个更好的建议编辑。如果他的背景线程工作10分钟,你的UI线程将被阻止10分钟。用户会认为应用程序被锁定,这正是@Mart试图避免的。您的更新是正确的。Thnx这是有效的,但是。。。我的头发静止不动。这个问题的解决方案是什么?@Martijn DoEvents(我相信)只会泵送消息队列一次,因此您必须在LoadAllData中随时调用它。+1。这个主意比我的好,应该解决GIF没有动画的问题。。。做起来更复杂,但不是很多,我认为值得付出努力。我的案例中的沉重负担是构建一个大型树视图。如果我将此方法放在一个线程中,则它无法访问treeview,因为treeview位于另一个线程中。@Martijn:您可以在该线程上调用该对象的事件。如果要更新GUI对象,就需要这样做。@Martijn这太不幸了。在WPF中,这将相对容易。你仍然可以这样做。您需要做的是构造一个真正的
    线程
    (即不使用线程池),并将其单元状态设置为STA。然后在工作线程中构造它,完成后将其传递回。然后,您必须将这个预构造的树添加到UI中,希望它不会因为线程亲和性问题而爆炸。这似乎比你在应用程序中需要的要复杂得多。@Martijn更新了答案。在LoadAllData方法的每隔一行中添加一个对DoEvents的调用,看看它是否适用于y
    ProgressBar1.Value = ProgressBar1.Value+1;
    if(ProgressBar1.Value == 100)
    { 
      timer1.Enabled = false; this.Hide();
      MessageBox.Show("Complete Loading...");
    }