c#BeginInvoke问题

时间:2010-08-02 19:30:00

标签: c# multithreading begininvoke

我有一个程序对数据库进行了一些大量调用,然后更新了UI。这导致了问题,因为大多数情况下它意味着UI没有响应。因此,我决定放置访问数据库的函数调用并在单独的线程中更新UI,所以现在我有这样的事情:

 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,那么就应该如何进行调用 - 这是正确的吗?我做错了吗?

4 个答案:

答案 0 :(得分: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);

    }

以下是有关如何使用BackgroundWorker获取其他详细信息的MSDN文章的链接。感谢Henk Holterman提出的建议:

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

答案 1 :(得分:1)

在“// Update UI here”中,确保使用Control.Invoke实际完成工作 - UI必须“触及”UI线程,这只有在您使用时才会发生Control.Invoke。

答案 2 :(得分:1)

BeginInvokeInvoke表示在UI线程上运行代码。在这种情况下,如果您从UI线程调用CallGetDBValues(),您将无法获得任何收益。

通常你会创建一个BackgroundWorker或后台线程,它将完成繁重的工作,它会调用需要更新的值的UI线程。

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 */
}

答案 3 :(得分: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);
    }
}