views:

94

answers:

4

I have a program that makes some hefty calls to the database and then updates the UI. This is causing problems because for most of the time it means that the UI in not responsive. I therefore decided that I wanted to put the function calls that access the database and update the UI in a separate thread, so now I have something like this:

 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

 }

 ...

However, it seems to make no difference whatsoever to the UI. I read somewhere that if the code to be run in a separate thread needed to update the UI then this was how the call should be made - is this correct? Am I doing something wrong?

+1  A: 

In the "// Update UI here", make sure to use Control.Invoke to actually do the work -- it's imperative that the UI only be "touched" by the UI-thread, and this only happens when you use Control.Invoke.

Kirk Woll
+2  A: 

You may be better served using the BackgroundWorker that is built-in to the .NET framework.

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

    }

Here's a link to the MSDN article on how to use the BackgroundWorker for additional details. Thanks to Henk Holterman for the suggestion to include this:

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

Robaticus
It's built into .NET, actually, not into C#.
John Saunders
True. Since we're a C# shop, I tend to always answer as "it's in C#" when I mean "it's in .NET" And I do understand that the equation here doesn't necessarily have the reflective property applied to it. Corrected it in my post.
Robaticus
Roboticus, you should link to MSDN or extend the Completed event a little. See the follow-up: http://stackoverflow.com/questions/3396662
Henk Holterman
Henk: Good point. I'll revise.
Robaticus
+1  A: 

BeginInvoke and Invoke means to run the code on the UI thread. In this case if you are calling CallGetDBValues() from the UI thread you are not going to gain anything.

Usually you will create a BackgroundWorker or background thread that will do the heavy lifting and it will Invoke back to the UI thread the values that need to be updated.

A BackgroundWorker will probably be the better solution (see Robaticus's answer), but here is a background thread version.

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 */
}
Jerod Houghtelling
A: 

I'm not sure of the syntax.. but the sytax I'm more familiar with is something like:

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);
    }
}
Shady M. Najib
Actually, after ready Kirk's answer I guess you'd better check his solution first of all
Shady M. Najib