C# How does a background thread tell a UI thread that it has finished doing something?

六眼飞鱼酱① 提交于 2019-12-18 11:49:16

问题


Scenario

Lets say you have a C# WinForms application that doing some data processing. You have a method that retrieves data from a database that is called by the UI thread. The background thread then runs off to do this task. You want the UI to carry on doing its thing and not be locked up and unresponsive.

QUESTION

How do you let the background thread run off and do its processing and then automatically alert the UI thread when it has returned the results?


回答1:


If you don't use a background worker thread (for whatever reason) then you must fire an event from your thread which is handled by the UI thread. For example I have this code that scans my mp3s and fires and event for each album found and then another event when it finished (or is stopped):

    public void Build()
    {
        FindAlbums(Root);

        // Final update
        if (Library_Finished != null)
        {
            Library_Finished(this, null);
        }
    }

    private void FindAlbums(string root)
    {
        // Find all the albums
        string[] folders = Directory.GetDirectories(root);
        foreach (string folder in folders)
        {
            string[] files = Directory.GetFiles(folder, "*.mp3");
            if (files.Length > 0)
            {
                // Add to library - use first file as being representative of the whole album
                var info = new AlbumInfo(files[0]);
                if (Library_AlbumAdded != null)
                {
                    Library_AlbumAdded(this, new AlbumInfoEventArgs(info));
                }
            }

            FindAlbums(folder);
        }
    }

Then in the UI thread (this is WinForms code):

    private void Library_AlbumAdded(object sender, AlbumInfoEventArgs e)
    {
        if (dataGridView.InvokeRequired)
        {
            dataGridView.Invoke((MethodInvoker)delegate { AddToGrid(e.AlbumInfo); });
        }
        else
        {
            AddToGrid(e.AlbumInfo);
        }
    }

    private void Library_Finished(object sender, EventArgs e)
    {
        if (dataGridView.InvokeRequired)
        {
            dataGridView.Invoke((MethodInvoker)delegate { FinalUpdate(); });
        }
        else
        {
            FinalUpdate();
        }
    }

I would, however, recommend that you investigate the background worker thread, as it does so much of the housekeeping for you. However, the same handling code would be needed in the RunWorkerCompleted event to update the UI.




回答2:


There are several ways of doing this, but the easiest way is to use a BackgroundWorker.

Essentially it has two delegates, the DoWork and the WorkCompleted. DoWork executes on a seperate thread and the WorkCompleted callback happens on the UI thread.

Here's more info: http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx




回答3:


You can use the BackgroundWorker to do your time-intensive processing in its DoWork event handler. Then handle the RunWorkerComplete event -- it will fire when the DoWork method is finished. While all this is going on, your UI thread will be happily running along.




回答4:


If you're using .NET 2.0 or newer, then this is made much easier with the BackgroundWorker thread. It has its own RunWorkerCompleted event that does just what you need.

I would highly recommend the BackgroundWorker in fact. It has the functionality most developers are after when creating threads. They're also easier to cancel gracefully, and they even have the ability to report progress.




回答5:


Try to use BackgrounWorker and register a handler to the its RunWorkerCompleted event.




回答6:


In Winforms you can use the .Invoke method (and check the .InvokeRequired property) to marshall a call back to the UI thread. You don't so much notify the UI thread - it keeps going on and doesn't wait for any sort of a completion, but you can interact with a control (for example, update the text property of a label) from another thread using the Invoke method.

You can also use the BackgroundWorker object (read MSDN to find out more about it), which implements a callback functionality to run some code on the UI thread after the background work is completed.




回答7:


If you are talking about a WinForm app, you can make changes to any UI objects using the Invoke method on your form (or any of the controls on the form). You can also find useful the InvokeRequired property




回答8:


You can store a reference to the UI thread Dispatcher by using Dispatcher.CurrentDispatcher (obviously in a method called by GUI thread). Using this object you can use the BeginInvoke or Invoke methods in your working thread to execute a method on the GUI thread notifying it that you have completed work. Personally I find this method to be slightly more flexible than using a background worker object and can produce slightly more readable code.




回答9:


There's an easy way of working with multiple threads in C#. It is called BackgroundWorker. You should check it out: BackgroundWorker Tutorial




回答10:


As was mentioned many times, the BackgroundWorker class can be used.

Alternatively, you could do something akin to the following:

void buttonGo_Clicked( object sender, EventArgs e )
{
    MyAsyncClass class = new MyAsyncClass();
    class.LongOperationFinished += (LongOperationFinishedEventHandler)finished;
    class.BeginLongOperation();
}

void finished( object sender, EventArgs e )
{
    if( this.InvokeRequired ) {
        this.BeginInvoke( (LongOperationFinishedEventHandler)finished, sender, e );
        return;
    }
    // You can safely modify the gui here.
}


来源:https://stackoverflow.com/questions/1684341/c-sharp-how-does-a-background-thread-tell-a-ui-thread-that-it-has-finished-doing

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!