I am using a visual control in my project that is from a library that I do not have the source to.
It takes too long to update (200ms, roughly) for good UI responsiveness with three of these controls on-screen at once. (I might need to update all three at once, which leaves my UI stuck for ~600ms while they are all thinking).
I have read some posts about TaskSchedulers, and am beginning to investigate the Parallel task features as a way of running each of these controls in their own thread. The platform will be multi-core, so I want to take advantage of simultaineous processing.
The problem is that I don't even know what I don't know about how to go about this, though..
Is there a suitable design pattern for running a control in a separate thread from the main UI thread in WPF?
Specifically: it is a third party map control, that when given a new location or zoom level takes far too long to redraw (~200ms). With perhaps three of these updating at a maximum of 4Hz - obviously they won't keep up..
I have encapsulated the WPF control in a usercontrol, and need to run each instance in it's own thread, while still capturing user input (mouse clicks, for example).
UPDATE: while I am feeling around for a solution, I have implemented the following so far.
My main (UI) thread spawns a thread that creates a new window that contains the control in question, and locates it in the correct position (so that it looks like it is just a normal control).
_leftTopThread = new Thread(() =>
{
_topLeftMap = new MapWindow()
{
WindowStartupLocation = WindowStartupLocation.Manual,
Width = leftLocation.Width,
Height = leftLocation.Height,
Left = leftLocation.X,
Top = leftLocation.Y,
CommandQueue = _leftMapCommandQueue,
};
_topLeftMap.Show();
System.Windows.Threading.Dispatcher.Run();
});
_leftTopThread.SetApartmentState(ApartmentState.STA);
_leftTopThread.IsBackground = true;
_leftTopThread.Name = "LeftTop";
_leftTopThread.Start();
Where CommandQueue
is a Thread-safe BlockingCollection Queue for sending commands to the map (moving the location, etc).
The problem is now that I can either
- have user input due to the
System.Windows.Threading.Dispatcher.Run()
call - or block on the CommandQueue, listening for commands sent by the main thread
I can't spin waiting for commands, because it would soak up all my thread CPU!
Is it possible to block and have the event message-pump working?
I've been looking into this as well, and the most relevant information I could find was in this blog post (however I have not tested it yet):
http://blogs.msdn.com/b/dwayneneed/archive/2007/04/26/multithreaded-ui-hostvisual.aspx
The problem with this method is that apparently the user won't be able to interact with the controls that are running in the new thread.
Well, I have a method that works - but it may well not be the most elegant..
I have a window that contains my third party (slow-rendering) control in the XAML.
My main (UI) thread contructs and starts this window on a thread:
I then get a handle to the window in the thread (after it has initialised):
.. and after putting a command onto the thread-safe queue that is shared with the threaded window:
.. I let it know it can check the queue:
The window can receive my message because it has hooked into the window messages:
..which it then can check:
..and then execute on the thread!
Easy as that.. :)