tags:

views:

174

answers:

3

Hi all,

I'm currently working on a WPF (with C# behind the scenes) system which requires rendering of data from many different files. Most of those files are AutoCAD documents. Each file comes with a set of data that we need to draw on screen essentially on the same canvas. Think of each file as a potential "layer" or overlay that needs to appear on screen.

At the moment, each graphics source is parsed and converted to a set of Path objects. Each collection of paths is rendered to it's own Canvas so that its visibility can be toggled on or off. Each of these canvases is made a child of a parent canvas which has a set of transforms applied to it. Those transforms are basic scale and translate render transforms which are used to support panning and zooming of the image that is being viewed.

This functionality currently works fine, but it's slow. We're rendering quite a few Path objects on screen and loading/creating those Path instances is taking quite a while.

The load speed in itself isn't so much of an issue; what really is the issue is that I need to create the Path instances on the UI thread, otherwise I can't render them all on the same canvas. Hence, while loading, the entire UI is locked up and the user can't do anything.

I have searched extensively on the web but can't seem to find a solution to the problem. I did stumble on one article (unfortunately I don't have the link anymore) which described a method of hosting items created on different threads on the same window. This didn't work for me at all. I tried a combination of things that I found in the article but I couldn't get anything to render at all.

So I guess the crux of my question is: Is it possible to create a set of UI objects, in particular Path objects, on different threads, then load them into a parent canvas on the main UI thread and have them all play nicely together? Any references, articles or tutorials would be greatly appreciated.

I'm looking forward to your help! Thanks for reading.

OJ

Edit 1: Each of the Path instances is just a single line with a colour. They aren't complicated. But it seems that creation of those objects themselves is what is taking the time (I might be wrong). Thanks!

A: 

Are you using the Dispatcher on which exists on every UIElement and provides the BeginInvoke method to run code on the right thread?

Have you read this MSDN article: Build More Responsive Apps With The Dispatcher

The Windows Presentation Foundation Threading Model is described here.

Mitch Wheat
Thanks for the response Mitch.The dispatcher doesn't really come into it. The dispatcher is what is used to update the UI when you are done doing the work on other threads. My case doesn't fit this scenario. I need to create the UI objects on another thread and then merge them back onto the UI thread. I'm not just doing arbitrary background work. Cheers.
OJ
PS. yes I have already read that article :) It doesn't help in my case. Thanks!
OJ
A: 

One possibility is to create the PathGeometry (the bulk of the work) on a separate thread, Freeze it, and set it into a Path created on your UI thread. (I haven't done this myself, only read about it.)

Here is an MSDN article on Freezable objects, of which PathGeometry is one, which states that they can be shared across threads (but no longer modified) once frozen. This may or may not suit your scenario.

Ben M
Ben, thanks for your response. I shall take a look at freezing them. I had in the past looked down this route, but for some reason discounted it (most likely without proper justification!). I'll give that a try and see how I go. Cheers.
OJ
Ah, I think I know why I discounted it. PathGeometry is freezable, but Path is not. Am I mistaken?
OJ
Yes, you're right (updated answer)--but you could create the PathGeometry on a separate thread, freeze it, and then set it into a Path (via the Data member) created on your UI thread.
Ben M
Thanks again Ben. I'll take a look at that option shortly. Thanks again for the help.
OJ
Ben, your mentioning of the Freezing has pointed me in a direction that I have managed to get working. I dont think I'll ever be able to just create all the UI elements on other threads and merge them the way I want, so I have used your comments as a starting point for the fix. Thanks for the help.
OJ
A: 

Just an idea. What if instead of dealing with UI objects, you work with XAML? It is just a string. For example, when your application starts, you spawn a background thread (BackgroundWorker) for each file. The background worker reads the file and puts together the XAML that has a canvas as the root UI element and then the paths generated from the data. You then return that XAML as a string back to the UI thread. The UI thread then uses XamlReader.Load method to load the XAML and adds the resulting canvas object to the parent canvas. You may even create the UI elements (child canvas and the paths it contains) on the worker thread and then get the resulting XAML to return to the main thread.

Mehmet Aras
Mehmet, thanks for your response. It's an interesting idea. I'm not sure what the performance implications of it would be, but it could be worth a shot. When I've finished playing with Ben's suggestions I'll give this one a whirl as well. Cheers!
OJ