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.