Creating new BackgroundWorker for every async task - c#

I create a new BackgroundWorker every time I need to do any Async task and after the work is done I Dispose it but I've a doubt if that completely disposes it because the Dispose method is implemented by System.ComponentModel.Component
In a typical run of the program, thousands of them may be created. Is it okay if millions of them (to be on the safe side) get created or should I do it some other way?
Most of the async work is I/O and I can't use async/await because I'm using .NET 4 (can't use 4.5).
I've wrapped the whole thing in this method:
public void AsyncDo(Action Action, Action ActionFinish = null)
{
using (BackgroundWorker bw = new BackgroundWorker()) {
bw.DoWork += () => Action();
bw.RunWorkerCompleted += (s, e) =>
{
if (ActionFinish != null)
ActionFinish();
if (e.Error != null)
OnException(e.Error);
};
bw.RunWorkerAsync();
}
}
Based on the answers, I've updated it with
Task t = new Task(action);
t.Start();
But I get a cross-thread error when I do actionFinish() by combining it with action or calling t.ContinueWith(). This wasn't the case in the BGW, it didn't require invoking for RunWorkerCompleted. I can't change every call to this method to make them use invoking, what should I do?

BackgroundWorker is specifically designed to allow code to run in the background with respect to the UI thread, while also allowing simple synchronization with the UI.
If you need to do any async task, just use Task - that's what it's designed for. If you don't have .NET 4+, you'll need to use Thread (or better, ThreadPool.QueueUserWorkItem) instead - but that's even more complex (while looking deceptively simple). As always, http://www.albahari.com/threading/ should be your starting point when trying to implement multi-threading (or asynchronous code in general) :)
EDIT:
To get a behaviour close to what you had originally with BackgroundWorker, you can simply add a continuation to run on the UI thread:
var task = Task.Factory.StartNew(yourAction);
task.ContinueWith(yourResultAction, TaskScheduler.FromCurrentSynchronizationContext());
All of this is strongly typed, so it's quite easy to pass an arbitrary value from the yourAction task (running on a worker thread) to the yourResultAction task (running on the UI thread). Note that the TaskScheduler.FromCurrentSynchronizationContext() must be run on the UI thread, of course.
You can wrap this in a simple helper function that will just take the two actions, and return a task (either the original task, or the continuation task - that depends on what you want to do with it).
Also, Microsoft.Bcl.Async brings most of .NET 4.5+'s await goodness to .NET 4.0 - after all, await is all in the compiler, it doesn't need a new runtime to work. Working with await is much simpler than working with continuations, especially when doing error handling.

A race condition occurs when two or more threads access shared data, for writing, at the
same time. (How to deal with race conditions is covered later in this chapter in the “Synchronizing
Resources” section.) If you try to update the UI from another thread, .NET Framework throws an
InvalidOperationException containing the following message: "Cross-thread operation not
valid: Control 'ctrlName' accessed from a thread other than the thread it was
created on."
To solve the problem, change the worker_RunWorkerCompleted method
as follows:
void _worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {
if (this.InvokeRequired) {
this.Invoke(
new Action(ActionFinish));
}
else {
ActionFinish();
}
}
In the worker_RunWorkerCompleted method, you now check the InvokeRequired
property. This property is defined in the Control class, and as such is present on all the controls on a page. InvokeRequired is set to false if you call it from the UI thread and true
otherwise.
The Invoke method takes as the first parameter a delegate, meaning any method can be
placed there. The new Action() constructor call is used to make sure that you
get a delegate. If your method has a different signature, you must change that constructor
accordingly. The rest of the parameters of the Invoke method are sent directly to the method
you want to run. Invoke places the method call in a queue to be picked up by the UI thread.
A better solution ?
void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e { this.Dispatcher.Invoke(()=> //statement); }
It is enough to call the Dispatcher.Invoke method in all the situations. This call
ensures that the lambda expression ()=> //statement is run by the UI thread,
regardless from which thread the method is called.

A BackgroundWorker and a task are both windows processes so I don't know why you need both. A class is also a process, but I like using a separate class rather than a task.
Imports System.ComponentModel
Module Module1
Sub Main()
Dim backgroundWorker As New MyBackGroundWorker
backgroundWorker.Dispose()
End Sub
End Module
Class MyBackGroundWorker : Implements IDisposable
Dim backgroundWorker As New BackgroundWorker
Sub Dispose() Implements IDisposable.Dispose
Me.Dispose()
End Sub
End Class

Related

Task.Wait for async method passes during application startup while it causes deadlock in WPF button handler

The behavior of Task.Wait() is unexpectedly different depending on the "environment" where invoked.
Calling Task.Wait() during application startup with below async method TestAsync passes (doesn't cause a deadlock) while the same code blocks when called from within a WPF Button handler.
Steps to reproduce:
In Visual Studio, using the wizard, create a vanilla WPF .NET framework application (e.g. named WpfApp).
In the App.xaml.cs file of the app file paste below Main method and TestAsync method.
In the project properties set Startup object to WpfApp.App.
In the properties of App.xaml switch Build Action from ApplicationDefinition to Page.
public partial class App : Application
{
[STAThread]
public static int Main(string[] args)
{
Task<DateTime> task = App.TestAsync();
task.Wait();
App app = new App();
app.InitializeComponent();
return app.Run();
}
internal static async Task<DateTime> TestAsync()
{
DateTime completed = await Task.Run<DateTime>(() => {
System.Threading.Thread.Sleep(3000);
return DateTime.Now;
});
System.Diagnostics.Debug.WriteLine(completed);
return completed;
}
}
Observe that the application starts properly (after 3sec delay) and that the "completed" DateTime is written to debug output.
Next create a Button in MainWindow.xaml with Click handler Button_Click in MainWindow.xaml.cs
public partial class MainWindow : Window
{
...
private void Button_Click(object sender, RoutedEventArgs e)
{
Task<DateTime> task = App.TestAsync();
task.Wait();
}
}
Observe that after clicking the Button, the application is deadlocked.
Why can't it pass in both cases?
Is there a way to change invocation (e.g. using ConfigureAwait at the correct task or somehow setting SynchronizationContext or whatever) so that it behaves identical in both invocations, but still synchronously waits for completion?
Update on limitations of the solution.
The async method like TestAsync comes from a library that cannot be changed.
The invocation code of the TestAsync method is nested within a callstack that cannot be changed either, and the code outside the callstck makes use of the returned value of the async method.
Ultimately the solution code has to convert the async method to run synchronous by not changing the method nor the caller.
This works well within UT code (NUnit) and during application startup, but no more within a handler of WPF.
Why?
There are a couple of different ways that you can handle this situation, but ultimately the reason there is a deadlock in one situation and not the other is that when called in the Main method SynchronizationContext.Current is null, so there isn't a main UI context to capture and all async callbacks are handled on thread pool threads. When called from the button, there is a synchronization context which is captured automatically, so all async callbacks in that situation are handled on the main UI thread which is causing the deadlock. In general the only way you won't get that deadlock is by forcing the async code to not capture the synchronization context, or use async all the way up and don't synchronously wait from the main UI context.
you can ConfigureAwait(false) inside of your TestAsync method so that it doesn't capture the synchronization context and try to continue on the main UI thread (this is ultimately what is causing your deadlock because you are calling task.Wait() on the UI thread which is blocking the UI thread, and you have System.Diagnostics.Debug.WriteLine(completed); that is trying to be scheduled back onto the UI thread because await automatically captures the synchronization context)
DateTime completed = await Task.Run<DateTime>(() => {
System.Threading.Thread.Sleep(3000);
return DateTime.Now;
}).ConfigureAwait(false);
You can start the async task on a background thread so that there isn't a synchronization context to capture.
private void Button_Click(object sender, RoutedEventArgs e)
{
var task = Task.Run(() => App.TestAsync());
var dateTime = task.Result;
}
you can use async up the whole stack
private async void Button_Click(object sender, RoutedEventArgs e)
{
Task<DateTime> task = App.TestAsync();
var dateTime = await task;
}
Given how you are using it, if you don't have to wait until the task is done, you can just let it go and it will finish eventually, but you lose the context to handle any exceptions
private void Button_Click(object sender, RoutedEventArgs e)
{
//assigning to a variable indicates to the compiler that you
//know the application will continue on without checking if
//the task is finished. If you aren't using the variable, you
//can use the throw away special character _
_ = App.TestAsync();
}
These options are not in any particular order, and actually, best practice would probably be #3. async void is allowed specifically for cases like this where you want to handle a callback event asynchronously.
From what I understand, in .NET many of the front ends have a single UI thread, and therefore must be written async all the way through. Other threads are reserved and utilized for things like rendering.
For WPF, this is why use of the Dispatcher and how you queue up work items is important, as this is your way to interact with the one thread you have at your disposal. More reading on it here
Ditch the .Result as this will block, rewrite the method as async, and call it from within the Dispatch.Invoke() and it should run as intended
Why can't it pass in both cases?
The difference is the presence of a SynchronizationContext. All threads start out without a SynchronizationContext. UI applications have a special UI thread(s) and at some point they need to create a SynchronizationContext and install it on that thread(s). Exactly when this happens isn't documented (or consistent), but it has to be installed at the point the UI main loop starts.
In this case, WPF will install it (at the latest) within the call to Application.Run. All user invocations from the UI framework (e.g., event handlers) happen within this context.
The blocking code deadlocks with the context because this is the classic deadlock situation, which requires three components:
A context that only allows one thread at a time.
An asynchronous method that captures that context.
A method also running in that context that blocks waiting for that asynchronous method.
Before the WPF code installed the context, condition (1) wasn't met, and that's why it didn't deadlock.
Is there a way to change invocation (e.g. using ConfigureAwait at the correct task or somehow setting SynchronizationContext or whatever) so that it behaves identical in both invocations, but still synchronously waits for completion?
We-ell...
This is a rephrasing of "how do I block on asynchronous code", and there's no good answer for that. The best answer is to not block on asynchronous code at all; i.e., use async all the way. Especially since this is GUI code, I'd say for the sake of UX you really want to avoid blocking. Since you're on WPF, you may find a technique like asynchronous MVVM data binding useful.
That said, there are a few hacks you can use if you must. Using ConfigureAwait is one possible solution, but not one I recommend; you'd have to apply it to all awaits within the transitive closure of all methods being blocked on (Blocking Hack). Or you can shunt the work to the thread pool (Task.Run) and block on that (Thread Pool Hack). Or you can remove the SynchronizationContext - unless the code being blocked on manipulates UI elements or bound data. Or there are even more dangerous hacks that I really can't recommend at all (Nested Message Loop Hack).
But even after putting in all the work for a hack, you'll still end up blocking the UI. The hacks are hard precisely because they're not recommended. It's quite a bit of work to give your users a worse experience. The far, far better solution (for your users and future code maintainers) is to go async all the way.

Why is using Task.Run() still blocking my UI?

I have a synchronous method I am calling with Task.Run() and my UI is being blocked and unresponsive. The method loads information from a database via COM Interop and I don't have any control over that.
public List<EdmAddInInfo2> GetInstalledAddins()
{
IEdmAddInMgr7 addinMgr = m_vault as IEdmAddInMgr7;
Array installedAddins = Array.CreateInstance(typeof(EdmAddInInfo2), 0);
addinMgr.GetInstalledAddIns(out installedAddins);
if (installedAddins?.Length > 0)
return installedAddins.OfType<EdmAddInInfo2>().ToList();
return null;
}
I am calling the method this way when my form is shown;
private async void LicensesForm_Shown(object sender, EventArgs e)
{
var m_addins = await GetInstalledAddins().ConfigureAwait(false);
toolStripStatusLabel2.Text = $"Loaded {m_addins.Count} addins.";
}
private async Task<List<EdmAddInInfo2>> GetInstalledAddins()
{
AddinManager addinMgr = new AddinManager(Vault);
var addins = await Task.Run(() => addinMgr.GetInstalledAddins()).ConfigureAwait(false);
return addins;
}
Usually I would use a BCW and be on my way, but I figured I would give Tasks a shot. Any ideas?
After the discussion in comments, I'm thinking that there is something deeper going on involving COM. One thing to be aware of when involving COM is that it uses the Dispatcher for receiving events, which has bitten me before. If the issue is related to COM one would probably need more information about what is going on and that digging might not be worthwhile. I wish I could be more helpful, but I think I'll have to default to advising the easy way out. Launch a thread to call GetInstalledAddins, assign the result to a local variable, and notify the UI of completion through the Dispatcher.
Also, from my original answer before editing to add the above,
var m_addins = await GetInstalledAddins().ConfigureAwait(false);
should be:
var m_addins = await GetInstalledAddins().ConfigureAwait(true);
This is because on the next line you assign to a UI element's Text property. This assignment must be done from the UI thread, which is active when you call GetInstalledAddins(), but because you then call ConfigureAwait(false) the execution continues after await on any thread the async manager (I forget what it's called) chooses.
One of the strengths of using async/await in UI code is that execution can (in normal situations) be resumed on the same thread the await call was made on. This way you can continue accessing UI objects after the await. But your call to ConfigureAwait(false) instructs the async/await engine that you don't care which thread the execution is resumed on (but in this case you really should care that the execution is resumed on the same thread).
The method loads information from a database via COM Interop and I don't have any control over that.
Well then, depending on the implementation of that method, it may not be possible to unblock the UI thread.
However, you could try this: if that type is allocating COM objects in its constructor, they may be getting tied to the UI thread. I would try creating the instance on the background thread:
private Task<List<EdmAddInInfo2>> GetInstalledAddins()
{
return Task.Run(() => new AddinManager(Vault).GetInstalledAddins());
}
Usually I would use a BCW and be on my way
BackgroundWorker would have the exact same problem.

how to properly call callback on dispatcher.begininvoke?

I assume that I can just call
var dispatcherOp = Application.Current.Dispatcher.BeginInvoke(Action());
dispatcherOp.Completed += dispatcherOp_Completed;
but then I am a little concerned. If begininvoke is asynchronous, then What prevents the dispatcher from completing the action before I get the returned dispatcher operation and attach to the completed event.
i assume that this must be impossible, but if so, I would like to know why.
You are correct; this is not safe. You should simply await the operation.
The answer is: nothing.
There are three possible approaches:
1.) You can decide that it is not important to wait for the operation to be executed. If so, then you are choosing the fire and forget strategy.
2.) You can decide that you want a synchronous request, so you await, like SLaks suggested.
3.) You can keep the request to be asynchronous, but use a callback.
Unfortunately Dispatcher does not have a callback function it takes for begininvoke.
Synchronous operation is not desired in my program, but I realized after a google search or two that I can lock on it like this
lock (this)
{
var dispatcherOp = Application.Current.Dispatcher.BeginInvoke(MyAction, DispatcherPriority.Normal);
dispatcherOp.Completed += dispatcherOp_Completed;
}
void dispatcherOp_Completed(object sender, EventArgs e)
{
lock (this)
{
}
}
and then lock again on the same object in the completed function so that the dispatcher can't complete till you have finished attaching your handler.
There is never a reason to use Dispatcher.BeginInvoke in a modern application.
If your code models a background operation, then use async/await, with IProgress<T> for any progress updates.
If your code models an asynchronous sequence, then use Rx (Reactive Extensions) with ObserveOn to update objects with UI thread affinity.

Invoke(Delegate)

Can anybody please explain this statement written on this link
Invoke(Delegate):
Executes the specified delegate on the thread that owns the control's underlying window handle.
Can anybody explain what this means (especially the bold one) I am not able to get it clearly
The answer to this question lies in how C# Controls work
Controls in Windows Forms are bound to a specific thread and are not
thread safe. Therefore, if you are calling a control's method from a
different thread, you must use one of the control's invoke methods to
marshal the call to the proper thread. This property can be used to
determine if you must call an invoke method, which can be useful if
you do not know what thread owns a control.
From Control.InvokeRequired
Effectively, what Invoke does is ensure that the code you are calling occurs on the thread that the control "lives on" effectively preventing cross threaded exceptions.
From a historical perspective, in .Net 1.1, this was actually allowed. What it meant is that you could try and execute code on the "GUI" thread from any background thread and this would mostly work. Sometimes it would just cause your app to exit because you were effectively interrupting the GUI thread while it was doing something else. This is the Cross Threaded Exception - imagine trying to update a TextBox while the GUI is painting something else.
Which action takes priority?
Is it even possible for both to happen at once?
What happens to all of the other commands the GUI needs to run?
Effectively, you are interrupting a queue, which can have lots of unforeseen consequences. Invoke is effectively the "polite" way of getting what you want to do into that queue, and this rule was enforced from .Net 2.0 onward via a thrown InvalidOperationException.
To understand what is actually going on behind the scenes, and what is meant by "GUI Thread", it's useful to understand what a Message Pump or Message Loop is.
This is actually already answered in the question "What is a Message Pump" and is recommended reading for understanding the actual mechanism that you are tying into when interacting with controls.
Other reading you may find useful includes:
What's up with Begin Invoke
One of the cardinal rules of Windows GUI programming is that only the
thread that created a control can access and/or modify its contents
(except for a few documented exceptions). Try doing it from any other
thread and you'll get unpredictable behavior ranging from deadlock, to
exceptions to a half updated UI. The right way then to update a
control from another thread is to post an appropriate message to the
application message queue. When the message pump gets around to
executing that message, the control will get updated, on the same
thread that created it (remember, the message pump runs on the main
thread).
and, for a more code heavy overview with a representative sample:
Invalid Cross-thread Operations
// the canonical form (C# consumer)
public delegate void ControlStringConsumer(Control control, string text); // defines a delegate type
public void SetText(Control control, string text) {
if (control.InvokeRequired) {
control.Invoke(new ControlStringConsumer(SetText), new object[]{control, text}); // invoking itself
} else {
control.Text=text; // the "functional part", executing only on the main thread
}
}
Once you have an appreciation for InvokeRequired, you may wish to consider using an extension method for wrapping these calls up. This is ably covered in the Stack Overflow question Cleaning Up Code Littered with Invoke Required.
There is also a further write up of what happened historically that may be of interest.
A control or window object in Windows Forms is just a wrapper around a Win32 window identified by a handle (sometimes called HWND). Most things you do with the control will eventually result in a Win32 API call that uses this handle. The handle is owned by the thread that created it (typically the main thread), and shouldn't be manipulated by another thread. If for some reason you need to do something with the control from another thread, you can use Invoke to ask the main thread to do it on your behalf.
For instance, if you want to change the text of a label from a worker thread, you can do something like this:
theLabel.Invoke(new Action(() => theLabel.Text = "hello world from worker thread!"));
If you want to modify a control it must be done in the thread in which the control was created. This Invoke method allows you to execute methods in the associated thread (the thread that owns the control's underlying window handle).
In below sample thread1 throws an exception because SetText1 is trying to modify textBox1.Text from another thread. But in thread2, Action in SetText2 is executed in the thread in which the TextBox was created
private void btn_Click(object sender, EvenetArgs e)
{
var thread1 = new Thread(SetText1);
var thread2 = new Thread(SetText2);
thread1.Start();
thread2.Start();
}
private void SetText1()
{
textBox1.Text = "Test";
}
private void SetText2()
{
textBox1.Invoke(new Action(() => textBox1.Text = "Test"));
}
Invoke((MethodInvoker)delegate{ textBox1.Text = "Test"; });
In practical terms it means that the delegate is guaranteed to be invoked on the main thread. This is important because in the case of windows controls if you don't update their properties on the main thread then you either don't see the change, or the control raises an exception.
The pattern is:
void OnEvent(object sender, EventArgs e)
{
if (this.InvokeRequired)
{
this.Invoke(() => this.OnEvent(sender, e);
return;
}
// do stuff (now you know you are on the main thread)
}
this.Invoke(delegate) make sure that you are calling the delegate the argument to this.Invoke() on main thread/created thread.
I can say a Thumb rule don't access your form controls except from main thread.
May be the following lines make sense for using Invoke()
private void SetText(string text)
{
// InvokeRequired required compares the thread ID of the
// calling thread to the thread ID of the creating thread.
// If these threads are different, it returns true.
if (this.textBox1.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(SetText);
this.Invoke(d, new object[] { text });
}
else
{
this.textBox1.Text = text;
}
}
There are situations though you create a Threadpool thread(i.e worker thread) it will run on main thread. It won't create a new thread coz main thread is available for processing further instructions. So First investigate whether the current running thread is main thread using this.InvokeRequired if returns true the current code is running on worker thread so call
this.Invoke(d, new object[] { text });
else directly update the UI control(Here you are guaranteed that you are running the code on main thread.)
It means that the delegate will run on the UI thread, even if you call that method from a background worker or thread-pool thread. UI elements have thread affinity - they only like talking directly to one thread: the UI thread. The UI thread is defined as the thread that created the control instance, and is therefore associated with the window handle. But all of that is an implementation detail.
The key point is: you would call this method from a worker thread so that you can access the UI (to change the value in a label, etc) - since you are not allowed to do that from any other thread than the UI thread.
Delegate are essentially inline Action's or Func<T>. You can declare a delegate outside the scope of a method which you are running or using a lambda expression(=>); because you run the delegate within a method, you run it on the thread which is being run for the current window/application which is the bit in bold.
Lambda example
int AddFiveToNumber(int number)
{
var d = (int i => i + 5);
d.Invoke(number);
}
It means that the delegate you pass is executed on the thread that created the Control object (which is the UI thread).
You need to call this method when your application is multi-threaded and you want do some UI operation from a thread other than the UI thread, because if you just try to call a method on a Control from a different thread you'll get a System.InvalidOperationException.

How to check a thread is done, then fill progress bar in C# / WPF

I am just working on my first GUI application on Windows.
I have a WPF GUI to a small C# utility which copies files. When the button is clicked to copy, I obviously don't want the GUI to hang. So, I fire off a new thread to run the method which copies the files. I assume I'm on track so far and there's no "better" way of doing it in C#?
Now, I have a ProgressBar which I want to appear filled when the thread is done. (It's fine running as indeterminate for now). How do I check when the copying is done?
So, so far I have:
Thread t = new Thread(delegate()
{
po.Organise(inputPath, outputPath, recursive);
});
t.Start();
PBar.IsIndeterminate = true;
And I want something after that that works like:
if (t.Done)
{
PBar.Value = 100;
}
Have a look at the BackgroundWorker class. It supports events like RunWorkerCompleted or ProgressChanged.
Have a look here, too (this is about threading in general + backgroundworker, again).
As already stated, consider the use of the BackgroundWorker class. It was designed for these situations and exposes events suited for what you are trying to accomplish.
Use the ProgressChangedevent to report progress incrementally and the RunWorkerCompleted for when the task finishes. Check the MSDN page for code samples.
Wrap the if (t.Done) block in its own method. Invoke this method from the end of your worker thread.
Also, you might want to give the worker thread a name to make it easier to spot in the debugger.
You need a callback method. This should get you started. It uses an AsyncCallback, which is the best way to tackle this type of issue.
I just looked up an example I've been using for a project and stripped out the code specific to my app:
System.Windows.Forms.MethodInvoker mi = new System.Windows.Forms.MethodInvoker(delegate()
{
// Do your file copy here
});
AsyncCallback ascb = new AsyncCallback(delegate(IAsyncResult ar)
{
this.Dispatcher.Invoke(new ThreadStart(delegate (){
// set progressbar value to 100 here
}), null);
});
mi.BeginInvoke(ascb, null);
The quick and easy hack would be to just update the UI at the end of your anonymous method in your thread. Obviously you can't update it directly, but you can use Dispatcher.Invoke:
Thread t = new Thread(delegate()
{
po.Organise(inputPath, outputPath, recursive);
Dispatcher.Invoke(new Action(()=>{PBar.Value = 100;}),null);
});
t.Start();
As a general Windows programming principal, you have to make calls to update the UI from the UI thread (the one that is processing messages through a message pump).
In Windows Forms, the way that this was done was through the implementation of the ISynchronizeInvoke interface on the Control class, primarily through the implementation of the Invoke method.
With the release of .NET 2.0, it was realized that a better mechanism was needed to marshal calls into the correct context. That's where the SynchronizationContext comes in.
This class abstracts the interface you would use for marshaling calls to different contexts, allowing for specific implementations depending on the context.
So whether or not Windows Forms is the environment, or WPF, one call can be made in the same way across those contexts with the same effect (marshaling the call).
In your particular case, because you are using a closure (anonymous method), you can take advantage of the fact that a SynchronizationContext is available to you (through the static Current property) at the invocation site of the Thread to provide the mechanism to call back to the UI thread from your background thread:
// Get the synchronization context.
// This is in the UI thread.
SynchronizationContext sc = SynchronizationContext.Current;
// Create the thread, but use the SynchronizationContext
// in the closure to marshal the call back.
Thread t = new Thread(delegate()
{
// Do your work.
po.Organise(inputPath, outputPath, recursive);
// Call back using the SynchronizationContext.
// Can call the Post method if you don't care
// about waiting for the result.
sc.Send(delegate()
{
// Fill the progress bar.
PBar.Value = 100;
});
});
// Make the progress bar indeterminate.
PBar.IsIndeterminate = true;
// Start the thread.
t.Start();
Note, if you don't care about waiting for the result of the call back to the UI thread, you can make a call to the Post method instead, which will dispatch the call to the UI thread without waiting for that call to complete.

Categories