2011-10-13 47 views
1

我有我真的不想在这一点上改写,旧的形式,所以我在做什么加载表格,然后加入它以新UI形式显示在面板上。这工作正常,但速度很慢。旧的表单会进行大量的数据加载和收集,效率不高。因此,大型记录最多需要30秒才能加载。如您所知,创建表单然后在加载旧表单时“锁定”主UI大约30秒。这是我试图阻止的行为。我想加载新表单,在空白面板中显示“加载”gif,然后一旦加载旧表单,请删除“加载”图像并将该表单添加为控件。C# - 跨线程操作 - 在线程创建控制,添加到主窗体

这里开始出现问题。

我试图创建一个后台工作,但是这会导致STA错误(旧形式有它自己的一些螺纹数据负载),因为我无法工人改为STA我停止了尝试。

我试图创建一个调用(而BeginInvoke),虽然这工作,它并没有真正加载旧形式的线程。它只是将它发送回UI线程并在那里完成工作。这又挂起了用户界面。 I.E .:不是我想要的。

我试图创建一个委托并触发其作为线程的事件,但我得到了相同的结果如下...

我创建一个线程,设置STA就可以了,开始它然后做了一段时间循环,DoEvents等待它完成。当然,这一切似乎都在向面板中添加表单,然后从“创建线程之外的线程”获取“Control'ChartForm'访问”。在此错误中,“ChartForm”是在线程中加载的旧图表。

我已经尝试了上面的方法,但我用来代替私有静态字段来保存旧形式的创建,然后一旦线程完成它添加到面板上。这是在while循环之后创建线程的方法。同样的错误。

所以,我用上面的方法在其他地方与数据表,并没有得到数据传回主线程与数据绑定使用的任何问题。我知道这有点不同,但我不认为这很难做到。

下面是我尝试使用的代码,似乎是最接近我想要的。

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

回答

3

在UI线程之外的任何其他线程上创建UI控件确实不是一个好主意。这在技术上是可行的,但难以管理,特别是如果新线程是“临时”线程。

你真正需要做的是重构出的ChartForm在做什么(在它出现建设工作?)并在后台线程上执行该操作,然后将其返回到UI线程,然后创建传递该工作结果的ChartForm。恕我直言,这是一个更好的设计反正;虽然它可能会为你做很多工作。

0

我不认为你想要什么,而不重构这个“旧形式”。只有一个UI线程,并且必须在该线程上创建所有UI元素才能显示给用户。

我建议重构最初没有任何数据(或可能带有加载图像)的表单,然后让表单使用BackgroundWorker启动后台任务来执行与UI无关的长时间运行的任务(将要一个数据库等)一旦工作人员完成,你就可以运行初始化表单数据元素的代码。这将在阻塞任务执行时尽可能长地保持UI响应。

+0

老实说,这就是我所害怕的。我知道UI需要在UI Thread上创建,我只是希望它不需要在那里创建。 –

0

我试着创建一个Invoke(和BeginInvoke),虽然这个工作, 它并没有真正加载线程中的旧窗体。它只是将其发回 回到UI线程并在那里完成工作。这又挂起了 用户界面。 I.E .:不是我想要的。

您必须更新主线程上的用户界面,您没有任何选择,如果它仍然挂着,那么您在错误的线程中进行计算。