2011-10-13 53 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 .:不是我想要的。

您必須更新主線程上的用戶界面,您沒有任何選擇,如果它仍然掛着,那麼您在錯誤的線程中進行計算。