我有一个旧的表单,我现在真的不想重写,所以我正在做的是加载表单,然后将其添加到新UI表单中的面板。这工作正常,但速度很慢。旧表单会进行大量的数据加载和收集,效率不高。因此,较大的记录最多需要30秒才能加载。如您所知,创建表单然后在加载旧表单时“锁定”主UI大约30秒。这是我试图阻止的行动。我想加载新表单,在空白面板中显示“正在加载”的gif,然后加载旧表单后删除“正在加载”图像并添加表单作为控件。
这就是问题所在。
我尝试过创建一个后台工作程序,但是这会导致STA错误(旧表单有一些自己的线程数据加载),并且由于我无法将工作者更改为STA,所以我停止了尝试。
我尝试创建一个Invoke(和BeginInvoke),虽然这个工作原理,它并没有真正加载线程中的旧表单。它只是将它发送回UI线程并在那里完成工作。这再次挂起了UI。 I.E。:不是我想要的。
我试图创建一个委托并将其作为线程中的事件触发,但我得到的结果如下所示......
我已经创建了一个线程,在其上设置STA,启动它然后执行一个while循环,并在其上等待DoEvents完成。当然这一切似乎都可以直接将表单添加到面板中,然后我从“创建它的线程以外的线程”中获取“控制'ChartForm'访问”。在此错误中,“ChartForm”是在线程中加载的旧图表。
我已经尝试了上面的方法,但是我使用私有静态字段来保存旧表单的创建,然后在线程完成后将其添加到面板中。这是在while循环之后创建线程的方法。同样的错误。
所以,我已经在DataTables的其他地方使用了上述方法,并且没有任何问题将数据返回到主线程以与DataBinding一起使用。我知道这有点不同,但我不认为这很难做到。
以下是我尝试使用的代码,它似乎与我想要的最接近。
private static _ChartForm;
private void LoadPatientChart()
{
ClearMainPanel(); // Removes any loaded ChartForms from Panel
if (_Patient == null) // Test to make sure a patient is loaded
return;
loadingPanel.Visible = true; // Displays the "Loading" gif
Thread thread = new Thread(new ThreadStart(this.GetChartForm));
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
while (thread.ThreadState != ThreadState.Stopped)
Application.DoEvents(); // Keeps the UI active and waits for the form to load
this.ChartPanel.Controls.Add(_ChartForm); // This is where the error is
loadingPanel.Visible = false; // Hide the "Loading" gif
}
private void GetChartForm()
{
ChartForm chartForm = new ChartForm(_Patient.AcctNum.ToString(), false);
chartForm.TopLevel = false;
chartForm.FormBorderStyle = FormBorderStyle.None;
chartForm.Dock = DockStyle.Fill;
chartForm.Visible = true;
_ChartForm = chartForm;
}
答案 0 :(得分:3)
在除UI线程之外的任何其他线程上创建UI控件真的不是一个好主意。这在技术上是可行的,但是很难管理,特别是如果新线程是“临时”的话。
你真正需要做的是重构ChartForm
正在做的工作(在构造它出现吗?)并在后台线程上工作,然后将其返回到你的UI线程,然后创建你的ChartForm
传递了这项工作的结果。恕我直言,这是一个更好的设计;虽然这可能对你有很多帮助。
答案 1 :(得分:0)
如果不重构这种“旧形式”,我不认为你想要的是什么。只有一个UI线程,必须在该线程上创建所有UI元素才能显示给用户。
我建议重构表单最初显示时没有任何数据(或者可能带有加载图像),然后让表单使用BackgroundWorker启动后台任务来执行与UI无关的长时间运行的任务(转到数据库等)一旦工作完成,您就可以运行初始化Form的数据元素的代码。这将在执行阻止任务的同时尽可能长时间地响应UI。
答案 2 :(得分:0)
我试图创建一个Invoke(和BeginInvoke),虽然这个工作, 它并没有真正加载线程中的旧表单。它只是发送它 回到UI线程并在那里完成工作。这又挂了 UI。 I.E。:不是我想要的。
您必须更新主线程上的用户界面,您没有任何选择,如果它仍然挂起,那么您在错误的线程中进行计算。