开发者

BackgroundWorker questions

开发者 https://www.devze.com 2023-01-08 13:50 出处:网络
I have UI WPF application. May by some one have any ideas why this code is not working? Case 1: BackgroundWorker worker = new BackgroundWorker();

I have UI WPF application.

May by some one have any ideas why this code is not working?

Case 1:

BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += delegate
{
   //some logic
};

worker.RunWorkerAsync();

In that case i am getting exception The calling thread cannot access this object because a different thread owns it. T开发者_开发技巧hen i changed it to this:

BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += delegate 
{ 
  this.Dispatcher.BeginInvoke(
    new Action(() =>  { //my code here }), null); 
}; 

After that UI getting frozen during executing this code. Like it is executing in the same thread

Case 2:

BackgroundWorker worker = new BackgroundWorker();
worker.RunWorkerAsync(new Action(() =>
{
 //some code here
}));

In that case code inside Action not executed.

//----------------------------------UPDATED--------------------------------------//

Thank you guy's for help The reason why my code didn't work properly is mentioned below. I did access some UI elements in background thread. Now I am getting all the values from UI elements before the call to BackgroundWorker. I now declare new variables, assign them all values from required UI elements, and then I am passing these variables to BackgroundWorker instead of the UI elements (which is what it originally did).


The problem with the first version is that inside "some logic" you are probably accessing WPF objects - you can't do that, WPF objects can only be accessed from the same thread that created them.

The problem with the second version is that you are starting a background thread that asks the main thread to do all the work and then exits, so you are doing all the work on the main thread (that also does all the UI work) and the UI freezes, essentially this is equivalent to not using a BackgroundWorker at all.

The third version, as Jon Skeet said, is simple incorrect usage and isn't supposed to work like you think it is.

So, what do you need to do?

You need to collect all the information from the UI in the main thread before starting the background worker, you can use only simple types (string, int, double, etc.) and thread-safe classes/structs, you can not use any WPF classes in the code executed by the BackgroundWorker.

After you finished collecting all the data you can call RunWorkerAsync, in you DoWork handler you can not read data from the UI - you can only access the data you prepared before, also you can not write into the UI - you have to save it somewhere else (class member for example) and copy it into the UI after the BackgroundWorker is finished.

The only exception to the "can't access WPF from another thread" rule is Freezable (and all classes that inherit from freezable) after the Freeze method is called, this makes the object read-only and thread-safe.


The second version won't do what you want, because the parameter to the overload of RunWorkerAsync which takes a parameter is just meant to be the value for DoWorkEventArgs.Argument. It's not meant to be the action to be executed - unless you provide an event handler which casts the value into an Action and calls it...

The first version should work - but as per Oded's comment, you haven't given any indication of what you mean by "not working"... nor have you specified whether both versions are failing or only one.


Another thing to be very wary of: if you're setting DoWork to an anonymous method, make sure you're not creating a closure over objects in the calling method. Those objects are on the calling method's thread, and if the DoWork method touches them, it is a Bad Thing.

A simple example:

MyClass foo = new MyClass();
worker.DoWork += delegate
{
   foo.MyProperty++;
};

I use anonymous methods pretty sparingly in general. Closures create all kinds of problems if you're not using them intentionally. And if you're using them intentionally, it's easy to end up writing code that's a little too subtle to modify a year down the line. Writing a named method with explicit parameters may take a little more time and code, but it's no harder than documenting what you're doing with a closure.

I don't use anonymous methods at all with the BackgroundWorker. Not only is there the risk that you'll rely on a closure without really thinking about all of the implications of it, but you've also very probably written code that can't be unit tested.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号