Question

...or...

"What evil in the depths of WPF have I awoken?"

I'm creating a Canvas on a background thread and rendering it to a bitmap. I've had this working in production code for over a year now without problems. I do the following:

  • create a Canvas object
  • create a new NameScope object
  • assign that NameScope to the Canvas
  • draw whatever I want on the Canvas
  • call canvas.Measure() with the Canvas's size
  • call canvas.Arrage() with the Canvas's available rect
  • call canvas.UpdateLayout()
  • render the Canvas

In the draw step, I have always just called canvas.Children.Add() to put UIElements onto the Canvas. This has always worked.

Now, for some inexplicable reason, in one specific case in the application I'm working on, the call to canvas.Children.Add() hangs indefinetely, blocking my background thread. I can't think of anything I'm doing differently between the code that has been working for over a year, and this one specific case.

Can anyone suggest possible reasons why a call to canvas.Children.Add() would hang like this?

Edit: The background thread is an STA thread (the background thread processing model was put in place because I couldn't process images using WPF on a MTA thread), so the thread apartment model shouldn't be the culprit.

Edit #2: While I understand why people are suggesting I try Dispatcher.BeginInvoke() from my background thread, I don't like that option for two reasons:

  1. I want my background thread processing to be synchronous on that thread. My background thread has a queue that other threads submit image jobs to, and my background thread processes each job as it gets to them. Using Dispatcher.BeginInvoke() adds another layer of complexity that I'd rather avoid.
  2. I've never needed to until now. Doing this background processing synchronously on my background thread has just plain worked. I'm trying to determine what could possibly be different about this bizarre edge case that causes this code to not work. If I can't get it to work, I'll end up rewriting this processing code without WPF, which I'd also rather avoid.
Was it helpful?

Solution

What apartment model are you using for your background thread?

I believe WPF needs to run on the STA thread. When you spawn the background thread, try settings it's apartment to STA.

Update:

If the STA thread is not the problem, then I would try breaking your canvas drawing up into chunks. Basically if you do a:

Dispatcher.BeginInvoke(...)

from your thread, the provided delegate gets pushed onto the back of the dispatcher queue, allowing other queued tasks to execute.

Update 2:

You could also try debugging into the source code for the Canvas object using the .NET framework reference sources. You can enable this by turning on "enable .net framework source stepping" in the debugging options under Tools->Options.

OTHER TIPS

Try calling Dispatcher.Run() in the background thread.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top