简体   繁体   中英

Cross-threading issue, BackgroundWorker and ReportProgress

I've got an [STAThread] main that contains something like this:

try
{
    // Start the port enumerator.

    Enumerator enumerator = new Enumerator();

    // Display the main window and start everything going.

    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);
    Application.Run(new TopViewForm(ref enumerator));
}
catch (Exception)
{
}

The enumerator object itself contains a background worker thread. The background work is initialised like this:

MyBackgroundWorker = new BackgroundWorker();
MyBackgroundWorker.WorkerSupportsCancellation = true;
MyBackgroundWorker.WorkerReportsProgress = true;
MyBackgroundWorker.DoWork +=new DoWorkEventHandler(MyBackgroundWorker_DoWork);
MyBackgroundWorker.ProgressChanged += new ProgressChangedEventHandler(MyBackgroundWorker_ProgressChanged);
MyBackgroundWorker.RunWorkerCompleted +=new RunWorkerCompletedEventHandler(MyBackgroundWorker_RunWorkerCompleted);
MyBackgroundWorker.RunWorkerAsync();

Now, in order to report progress back to the main form (the instance of TopViewForm), the thread in Enumerator is calling ReportProgress with some appropriate user object. ReportProgress, I assume, will arrive in the form of ProgressChanged event and be executed on the main UI thread, which is the thread the Enumerator itself was created on (ie not the BackgroundWorker's thread).

Given that this is the case, how is it possible that I'm getting a cross-thread violation error when I try to set a node in a TreeView on the main process thread in response to an event from this object? The ProgressChanged categorically does not appear to be run on the main process thread, looking at the call stack.

I assume then, that Application.Run generates a new thread and runs the form with that? But the documentation says otherwise. Either I've made a dumb error or there's something I don't understand here.

Does anyone have any thoughts?

I believe that the progress changed event is running before Application.Run is first called. If you don't start the background worker from Main , but rather from inside one of the forms you will be sure that the message loop already exists when the background worker is created and starts reporting progress.

BackgroundWorker relies on a current SynchronizationContext being set in order to function. ProgressChanged event is implemented as SendOrPostCallback Delegate and as it stated in msdn documantation SendOrPostCallback represents a callback method that you want to execute when a message is to be dispatched to a synchronization context. Adding BackgroundWorker to a form in a Form designer sets SynchronizationContext properly. In your case BackgroundWorker has no SynchronizationContext assigned.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM