2010-08-02 60 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