Option 1: Rendering event
Do your calculations on the separate thread, but queue changes to the UI and update them on the Rendering event. It would look like this:
PresentationSource.FromVisual(window).CompositionTarget.Rendering += (obj, e) =>
{
foreach(var update in _queue)
UpdateUI(update);
}
This code assumes _queue's is a thread safe (synchronized) queue. You can create such a queue class or download one. Alternatively you can surround the "foreach" with a "lock(_queue)".
The reasons this is better than Dispatcher.BeginInvoke() are: 1. It is called just before each frame so if the frame rate goes down it is called less frequently, and 2. It processes the changes in batches.
Option 2: Multiple UI threads
You can run a portion of your UI on a separate thread by using a separate hWnd. You can use WindowsFormsIntegration for this or use some Win32 magic. Here is one way to do it:
- In the new thread, construct the Window and show it (don't forget to Appliation.Run())
- Once the new window is shown, get the hWnd using
((HwndSource)PresentationSource.FromVisual(window)).Handle
- Pass the hWnd back to the main UI thread using a Monitor or ManualResetEvent
- Use WindowsFormsHost to construct a container for the hWnd and add it to your UI
- Handle resize events in the main UI, passing them down to the contained window
Option 3: Animations
You can create your own custom Animation-derived classes to animate your UI items. These can use data precaculated from the model. The advantage of doing this is precise time synchronization: Every time your code is called it knows exactly "when" (in animation time) it is calculating the position for. So if some other program hogs the CPU or GPU for a second and slows down and the frame rate, the animation still proceeds smoothly at the lower frame rate.
To do this, subclass DoubleAnimationBase
and override GetCurrentValueCore() to do your custom calculation, combined with the required Clone() and CreateInstanceCore() overrides. Then use this to animate your properties.
If simply animating Double properties of existing objects is not enough, it is possible to create an animation that produces entire objects such as Geometry, Geometry3D, Drawing, Drawing3D or even UIElement. To do this, subclass AnimationTimeline and override GetCurrentValue() along with the others.
The advantage of using animations is the same as with the rendering event, except you can let WPF handle all the clock synchronization and replay speed issues for you instead of doing it yourself. It may also result in less code if you can animate only the properties that are changing.