2010-08-02 27 views
1

我有一個程序會對數據庫進行一些重大調用,然後更新UI。這是造成問題的原因,因爲在大多數情況下,這意味着UI不響應。因此,我決定,我希望把訪問數據庫的函數調用和更新在一個單獨的線程的UI,所以現在我有這樣的事情:c#BeginInvoke問題

private delegate void CallAsyncDelegate(); 

private void CallGetDBValues() 
{ 
     // Call GetDatabaseValues in new thread 
     CallAsyncDelegate callGetDatabaseValues = new 
      CallAsyncDelegate(GetDatabaseValues); 
     BeginInvoke(callGetDatabaseValues); 
} 

private void GetDatabaseValues() 
{ 
    // Get lots of data here 


    // Update UI here 

} 

... 

但是,它似乎毫無任何區別的UI。我在某處讀到,如果要在單獨的線程中運行的代碼需要更新UI,那麼這就是應該如何進行調用 - 這是正確的嗎?難道我做錯了什麼?

+0

你明白了倒退;如果您的代碼已經在單獨的後臺線程中運行,並且您需要從中更新UI,那麼您需要使用BeginInvoke方法,該方法允許您在UI線程上執行UI更新代碼。就你而言,你已經在UI線程上執行了代碼,但是你想要在單獨的後臺線程上執行工作代碼。在這裏尋找一個建議使用BackgroundWorker組件的答案......它是一個可以添加到UI窗體以在分離線程上執行代碼的組件。 – 2010-08-02 19:34:01

+0

您可以在BCL中使用MethodInvoker而不是定義您自己的代理 – thecoop 2010-08-02 19:39:23

回答

3

使用內置於.NET框架的BackgroundWorker可能會更好地服務您。

BackgroundWorker bw = new BackgroundWorker(); 
    bw.DoWork += new DoWorkEventHandler(bw_DoWork); 
    bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted); 
    bw.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged); 
    bw.WorkerReportsProgress = true; 

    void bw_ProgressChanged(object sender, ProgressChangedEventArgs e) 
    { 
     // update UI with status 
     label1.Text = (string)e.UserState 
    } 

    void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
    { 
     //Check for cancel 
     if(e.Cancelled) 
     { 
      //Handle the cancellation. 
     { 

     //Check for error 
     if(e.Error) 
     { 
      //Handle the error. 

     }  

     // Update UI that data retrieval is complete 
    } 

    void bw_DoWork(object sender, DoWorkEventArgs e) 
    { 
     // Get data 
     //foreach to process data 
     //Report progress 

     bw.ReportProgress(n, message); 

    } 

下面是MSDN文章中有關如何使用BackgroundWorker獲取更多詳細信息的鏈接。由於亨克Holterman的建議,包括此:

http://msdn.microsoft.com/en-us/library/cc221403%28VS.95%29.aspx

+0

它實際上已內置到.NET中,而不是C#中。 – 2010-08-02 19:42:52

+1

是的。由於我們是C#商店,當我的意思是「它在.NET中」時,我傾向於總是以「它用C#」的形式回答。而且我明白,這裏的等式不一定具有反射屬性。在我的文章中更正了它。 – Robaticus 2010-08-02 20:03:13

+0

Roboticus,你應該鏈接到MSDN或擴展Completed事件一點點。見後續:http://stackoverflow.com/questions/3396662 – 2010-08-03 14:04:13

1

在「// Update UI here」中,請確保使用Control.Invoke來實際完成這項工作 - UI必須僅由UI線程「觸摸」UI,並且這僅在您使用Control.Invoke。

1

BeginInvokeInvoke指運行在UI線程上的代碼。在這種情況下,如果您從UI線程調用CallGetDBValues(),則不會獲得任何收益。

通常你會創建一個BackgroundWorker或後臺線程,它將完成繁重的工作,它會調用需要更新的值到UI線程。

A BackgroundWorker可能是更好的解決方案(請參閱Robaticus的答案),但這裏是後臺線程版本。

private delegate void CallAsyncDelegate(); 

private void button_Click(object sender, EventArgs e) 
{ 
    Thread thread = new Thread(GetDBValues); 
    thread.IsBackground = true; 
    thread.Start(); 
} 

private void GetDBValues() 
{ 
    foreach(...) 
    { 
     Invoke(new CallAsyncDelegate(UpdateUI)); 
    } 
} 

private void UpdateUI() 
{ 
    /* Update the user interface */ 
} 
0

我不知道語法的..但我更熟悉的是語法時才類似:

public delegate object myDelegate(object myParam); 

Public class MyClass 
{ 
    public static void Main() 
    { 
     myDelegate d = new myDelegate(myMethod); 
     d.BeginInvoke (new object()); 
    } 

    static void myMethod(object myParam) 
    { 
     // do some work!! 
     return new object); 
    } 
} 
+0

事實上,在準備好Kirk的回答之後,我想你最好先檢查他的解決方案 – 2010-08-02 19:57:25