views:

157

answers:

3

I'm writing an application which will display the current image seen by a camera and it needs to update the shown image in real time, or close to it. Essentially, I have a camera with which I can capture images and I need to capture one every, say, 1 second and display that image to the screen. Currently, my application has an Image control and I'm capturing a BitmapImage from the camera and setting this as the Image.Source. My trouble is getting this to continuously update. Unfortunately, I have no experience dealing with something like this that has to update itself forever (or until the application I'm writing is closed) and honestly there seems to be very little to none (that I have been able to unearth) on the web about doing something like this in WPF/C#. I suspect I'll have to spawn a thread to perform the image capturing, but honestly, that's part of my issue--I have very little experience working with threads and am a bit confused on how all that works. Thanks so much for any help you can provide.

A: 

You should read up on data binding in WPF. WPF is riddled with observer patterns to update the display as soon as a bound data item is changed. The fact that you are changing the Image.Source instead of changing the content of the image may be what's confusing things. You need to set up the image control in XAML as data-bound to a bitmap object (probably a field of your form) and then alter or reload the bitmap object as needed. The data-bound image control should redraw itself automatically with each change to the bitmap object.

Since you mention background threads, you need to be careful to modify the properties of UI elements (Image, Bitmap) only on the UI thread. If you receive a new image in the background thread and want to show it in the UI, you will need to synchronize that update to the UI thread. See Dispatcher.Invoke()

dthorpe
As it is WPF, using the [Dispatcher](http://msdn.microsoft.com/en-us/magazine/cc163328.aspx) is the WPF way for synchronizing with the UI thread.
chibacity
Perhaps I'm not understanding this correctly...there isn't a Content property for Image controls, so I bound the Source to a Property of the form. I tried:<Image Source="{Binding Path=CurrentImage}" Name="img_imageViewer"/>However, the problem there is that when I set this.CurrentImage programmatically later, it never updates the Image control-I just get a blank Image. Am I doing something incorrectly? Also, so to update the image every second (or some time period), do you advise using a background thread to change the form CurrentImage property or something else? Thanks again!
JToland
@chibacity: Good point. Edited to fix. Thanks.
dthorpe
@JToland: If your are binding to a property that you implement, you also need to implement INotifyPropertyChanged on the class that contains that property so that the data binding mechanism can find out that the property has changed and respond accordingly. In your example, this would be the form class. See an example implementation on MSDN: http://msdn.microsoft.com/en-us/library/ms229614.aspx
dthorpe
@JToland: If the acquisition or loading of that bitmap is computationally expensive or involves blocking operations (waiting for a serial port, for example) then that would be a good reason to put the bitmap acquisition into a background thread so it doesn't freeze your UI. Otherwise, I'd skip the added complexities of threads and just load your bitmap in a 1 second timer event on the UI thread. You can do a lot of stuff with threads, but you can do a lot of the same stuff without threads, too. ;>
dthorpe
+2  A: 

To make the data binding get updated properly, you can use INotifyPropertyChanged. Just add a reference to System.ComponentModel:

using System.ComponentModel;

Then inherit the interface:

MyWindow : INotifyPropertyChanged

Then add the following code:

public event PropertyChangedEventHandler PropertyChanged;

private void NotifyPropertyChanged(String info)
{
    if (PropertyChanged != null)
    {
        PropertyChanged(this, new PropertyChangedEventArgs(info));
    }
}

Finally, add your property that you want to bind to.

private BitmapImage currentImage;
public BitmapImage CurrentImage{get{return currentImage;} set{currentImage=value;NotifyPropertyChanged("CurrentImage");}}

Finally, in your xaml, change the binding to {Binding CurrentImage} and then for the window, set the data context to relative source self... this would be a property for the window:

DataContext="{Binding RelativeSource={RelativeSource Self}}"

That should get the binding working properly. Doing things on a separate thread would require the dispatcher

jle
Combining this answer with dthorpe's below works PERFECTLY! Thanks so much for making this very clear and dummy-proof; it was very much appreciated.
JToland
A: 

I am in a similar situation, except that the Image is passes to my WPF client via WCF. So I have set a timer and call the WCf service every1 second. But when I assign the ImageSource to the bitmapImage the image is flickering, as in I get a white screen ,Image, whit screen, image How to make it continuous?

xaria
@xaria: Have you tried using the methods discussed above? I know when my CurrentImage property is changed, and when I'm using the notifier as discussed above, my image is properly changing without any sort of flicker. Perhaps your 'current' image is being cleared from the Property, or memory, or whatever, before the 'new' image is actually set?
JToland
No I have not tried it yet, as I do not completely understand what is to be done. Do I change my window which has the Image element to inherit from INotifyPropertyChanged?So that MainWIndow : Window changes to MainWindow : INotifyPropertyChanged ??Then how about the other elements in the window?
xaria