You can do this a few ways, Dispatcher, Task, Backgroundworker, but following along more with what you were doing, write it this way instead:
Declare the Action delegate separately if you want, but this is basically what you need to do. The important thing is that an update to the UI needs to be done from a thread separate to the rest of your code. See DispatcherPriority
]. Based on priority, rendering happens after code execution. So if you're looping through some code and updating the progressbar within the same thread, then the progressbar has to wait for the looped code to finish before it can use the thread to render the update. For the same reasons, any kind of heavy work should be separated from the main UI thread also or you lock out the Input level and the application's window becomes unresponsive until the work is done.
On a side note, priority is also why you would use Background for most UI updates. The next priority up is Input. Any user interaction with the UI or moving the window for example would be Input. Above that is Loaded and if you used that to update the control then you have a similar issue as before where this time your control would be updating and rendering like it should, but you would be locked out of interacting with the UI until it was finished because the Input level is forced to wait.