MighMoS
MighMoS

Reputation: 1254

On creating expensive WPF objects and multithreading

The classic advice in multithreading programing is to do processor heavy work on a background thread and return the result to the UI thread for minor processing (update a label, etc). What if generating the WPF element itself is the operation which is expensive?

I'm working with a third party library which generates some intense elements, which can take around to 0.75s - 1.5s to render. Generating one isn't too bad, but when I need to create 5 of them to show at once it noticeably locks the UI (including progress spinners). Unfortunately, there isn't any other place to create them because WPF is thread affine.

I've already tried DispatcherPriority.Background but its not enough. What is the recommended way to deal with this problem?

Upvotes: 1

Views: 219

Answers (1)

Ian Griffiths
Ian Griffiths

Reputation: 14547

If the objects being created derived from Freezable, then you can actually create them on a different thread than the UI thread - you just have to call Freeze on them while you're on the worker thread, and then you can transfer them over. However, that doesn't help you for items that don't derive from Freezable.

Have you tried creating them one at a time? The following example doesn't do any useful work but it does show how the basic structure for doing a lot of work in little bits:

int count = 100;
Action slow = null;
slow = delegate
{
    Thread.Sleep(100);
    count -= 1;
    if (count > 0)
    {
        Dispatcher.BeginInvoke(slow, DispatcherPriority.Background);
    }
};
Dispatcher.BeginInvoke(slow, DispatcherPriority.Background);

The 'work' here is to sleep for a tenth of a second. (So if you replace that with real work that takes about as long, you'll get the same behaviour.) This does that 100 times, so that's a total of 10 seconds of 'work'. The UI remains reasonably responsive for the whole time - things like dragging the window around become a bit less smooth, but it's perfectly usable. Change both those Background priorities to Normal, and the application locks up.

The key here is that we end up returning after doing each small bit of work having queued up the next bit - we end up calling Dispatcher.BeginInvoke 100 times in all instead of once. That gives the UI a chance to respond to input on a regular basis.

Upvotes: 1

Related Questions