简体   繁体   English

Winforms:如何显示“加载”表单?

[英]Winforms: How to display a “loading” form?

I have a grid and when a row is double clicked a form is loaded. 我有一个网格,当双击一行时,表单被加载。 However a lot of data must be loaded, so I'd like to display a simple form with the text 'loading, please wait..'. 但是必须加载大量数据,所以我想显示一个带有文本'loading,please wait ...'的简单表单。 And when all loading is finished, the form must disappear. 当所有装载完成后,表格必须消失。

This is what I have right now, but it doesn't work: 这就是我现在所拥有的,但它不起作用:

Code that invokes the form with lots of data: 调用包含大量数据的表单的代码:

FormWithLotData form = new FormWithLotData();
form.ShowDialog(this);

Constructor of FormWithLotData: 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);

Hope you can help me out. 希望你能帮助我。

EDIT: I'd like to show an animated gif on the loading form. 编辑:我想在加载表单上显示动画GIF。

SOLUTION: I've created a background worker. 解决方案:我创建了一个后台工作者。 The DoWork event handles all the loading and by using the invoke() method I add nodes to the treeview. DoWork事件处理所有加载,并使用invoke()方法将节点添加到树视图中。 Now, the GUI doesn't hang and the user don't have the idea that the application is hanging. 现在,GUI不会挂起,用户也不知道应用程序正在挂起。

You need to reverse your code. 您需要撤消您的代码。

The constructor of FormWithLotData is running in the UI thread. FormWithLotData的构造函数在UI线程中运行。 This is the thread that must show your FormIsLoading form. 这是必须显示FormIsLoading表单的主题。 So instead of trying to display this form using the new Thread, do your data loading with it. 因此,不要尝试使用新线程显示此表单,而是使用它加载数据。

The DoEvents way others have suggested is the easiest to implement and (possibly? never done it myself) may work well. 其他人建议的DoEvents方式最容易实现,并且(可能?从未自己完成)可能效果很好。

The better pattern to use is to do your data loading on a worker thread. 更好的模式是在工作线程上进行数据加载。 Before you show your FormWithLotData, Begin loading data on a background thread and show your Loading dialog. 在显示FormWithLotData之前,开始在后台线程上加载数据并显示“加载”对话框。 The method that loads the data should have a callback method into the Loading dialog to signal when it should Close(). 加载数据的方法应该在“加载”对话框中有一个回调方法,以指示何时应该关闭()。 Once it closes you can then construct a new FWLD, pass it the already loaded data, and Show it. 一旦关闭,您就可以构建一个新的FWLD,将已经加载的数据传递给它,并显示它。

Trying to load your data after the form has already been invoked mixes your UI with your data operations, forcing your form to not only be in charge of the UI but also be in charge of data retrieval. 在调用表单后尝试加载数据会将UI与数据操作混合在一起,迫使您的表单不仅要负责UI,还要负责数据检索。 Bad for KISS and Single Responsibility, imho. 对于KISS和单一责任不利,imho。


After your update, it seems like DoEvents is going to be the only real answer to your question, but with some caveats. 更新后,似乎DoEvents将是您问题的唯一真正答案,但有一些警告。

You will not be able to show another form MODALLY while you construct your tree. 在构建树时,您将无法以模式显示另一个表单。 You will still have to do your heavy work within your form's constructor. 你仍然需要在表单的构造函数中做繁重的工作。 You will still have to hide your main form and Show() (not ShowDialog) your loading form. 您仍然需要隐藏您的主表单和Show()(而不是ShowDialog)您的加载表单。 You will also have to call DoEvents at every single possible moment while constructing your tree. 在构建树时,您还必须在每个可能的时刻调用DoEvents。 Its not exactly an elegant solution, but it will probably be your best bet at this point. 它不是一个优雅的解决方案,但它可能是你最好的选择。

how about ... 怎么样 ...

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

// ... load data ...

frm.Close();

In the Form_Load event, add the following: 在Form_Load事件中,添加以下内容:

this.Visible = true;
Application.DoEvents();

before any other processing occurs. 在任何其他处理发生之前。 The Application.DoEvents caused the UI to show the form at the current state, where normally the UI thread is locked while you other processing is taking place. Application.DoEvents导致UI在当前状态下显示表单,通常在执行其他处理时UI线程被锁定。

Don't do your LoadAllData() directly in a UI thread, instead start up a background thread to do it. 不要直接在UI线程中执行LoadAllData() ,而是启动后台线程来执行它。 The in your Form_Loaded event handler, use an AutoResetEvent and wait till it becomes signalled by the background data retrieving thread. 在Form_Loaded事件处理程序中,使用AutoResetEvent并等待它被后台数据检索线程发出信号。 Once it is signalled you can then continue to do whatever you need to do with the data, like bind it into the UI. 一旦发出信号,您就可以继续对数据进行任何操作,例如将其绑定到UI中。

This method is still a little clunky for various reasons, but it will get you started. 由于各种原因,这种方法仍然有点笨拙,但它会让你开始。

Edit: i was being lazy with my answer above... a better option is to pass a delegate (callback) to the background thread, when the delegate is invoked (upon completion of the data retrieval) it marshals itself back on to the UI thread, and starts doing the required work with the data. 编辑:我上面的答案是懒惰...一个更好的选择是将一个委托(回调)传递给后台线程,当调用委托时(在完成数据检索时)它将自己编组回UI线程,并开始对数据进行必要的工作。

  1. Inside your form, you can use a Timer control to simulate loading using ProgressBar when it reaches 100 it unloads the form or any kind of animation. 在表单内部,您可以使用Timer控件在ProgressBar达到100时使用ProgressBar模拟加载,它会卸载表单或任何类型的动画。

    for progress-bar code just add the control from the toolbox and then write the following code: 对于进度条代码,只需从工具箱中添加控件,然后编写以下代码:

 ProgressBar1.Value = ProgressBar1.Value+1; if(ProgressBar1.Value == 100) { timer1.Enabled = false; this.Hide(); MessageBox.Show("Complete Loading..."); } 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM