views:

53

answers:

3

I'm currently working on a WPF/C# application which is connected to an external camera. This application gets a snapshot from the camera, then does some analysis and displays it to the screen via a user interface. There are also many other UI elements on the interface (such as buttons, menus, and comboboxes). Right now, while the application is running, the user interface is notably slowed--for instance, a combobox, once clicked, may freeze up for just a second before opening. Then it may freeze again before allowing a user to select a value. I'm pretty sure this is due to the getting of the snapshot happening on the same thread as all the UI, however, I am very naive about using threads properly and really am at a complete loss as how I can go about correctly this issue. Basically, I want the UI to not be noticable slower at all even though the fastest I can retrieve images seems to be about 1 / second from the camera. How could I go about splitting this into multiple threads? AND would that even help my problem any? Thanks so much; any help is deeply appreciated.

+1  A: 

If you have access to .NET 4, you could set up a Task to get the snapshot and a continuation to update the GUI. The task will be run on a thread pool thread leaving your UI responsive. Remember to use the FromCurrentSynchronizationContext scheduler for the continuation.

var uiScheduler = TaskScheduler.FromCurrentSynchronizationContext;
var task = Task.Factory.StartNew( () => { // Get snapshot })
    .ContinueWith(t => { // update ui }, uiScheduler);
Brian Rasmussen
Unfortunately, I'm forced to write this with .NET 3.5.
JToland
+3  A: 

If not using .NET 4, you can use the BackgroundWorker.

BackgroundWorker worker = new BackgroundWorker();

worker.DoWork += (s, e) => 
{
    // Perform things on the background thread here.
};
worker.RunWorkerCompleted += (s, e) =>
{
    // Code to be run after the thread is done, on the UI-thread.
};
worker.RunWorkerAsync();
Jeremy
If I have an object from the UI thread (specifically an Image object), can I set it equal to e.Result in the RunWorkerCompleted method? The way I have it now, I cause an error because it says I'm trying to access an object from another thread in the RunWorkerCompleted. What other way can I set my Image object?
JToland
Yes, if you set e.Result in DoWork, you should be able to assign myVar = e.Result in the RunWorkerCompleted code; that runs on the UI-thread and shouldn't trigger the cross-thread error.
Jeremy
But it does. I have a TransformedBitmap object, CurrentImage, which is a property of my MainForm window and actually is bound to an Image object (it's designed such that when I set CurrentImage to something the Image object displayed on the UI updates itself to the newest image). Right now, when I say this.CurrentImage = (TransformedBitmap)e.Result;, I get the cross-thread error. I've been reading about BackgroundWorkers for a couple of hours now and I can not for the life of me figure out why I should be having these issues...
JToland
I've discovered the porblem; it was because I was using a freezable object, and the problem was that in my bitmap needed to be "freezed" before sending it in UI thread. I've gotten it working. Thanks for your help!
JToland
Glad to hear it; cheers!
Jeremy
A: 

You Can use background worker , it is nice event based asynchronous mechanism which really does not include user created threads ,though internally uses thread pool . So use it as a starting point.

You can use BGs Dowork event to do CPU incentive task. It supports progress notification so that you can notify ur users about how much work is done.

Only caution has to be taken when updating any ui component, because here you need tdonthink about Dispather.invoke

See more at MSdn.

saurabh