WPF binding image from camera - c#

Hello I'm new around here, used to be rather passive reader.
I'm learning WPF + MVVM, and I think I'm missing something in the whole binding concept.
I'm using flycapture2 SDK for point grey camera, according to attached examples I should call _ProgressChanged on image receive event and bind received image to the image.source property
private void m_worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
BitmapSource image = (BitmapSource)e.UserState;
this.Dispatcher.Invoke(DispatcherPriority.Render,
(ThreadStart)delegate ()
{
image.Source = image;
}
);
}
But that doesn't look good to me, because we just overwrite the source image every time a new image arrives.
What I tried to do instead (following some online tutorials) was to bind the Image control source property through ViewModel property Images_s with the window code behind (setting DataContext to ViewModel) and then I would expect that everytime I change the viewModel.Images_s it should update the UI.
Unfortunately that doesn't work and instead I got an empty window.
Also - Do I need to dispatch this task? As I imagine binding should update UI itself on the event of image variable change in the Window code behind (Or am I overestimating WPF super powers?)
Thanks,
<Image Name="myImage" Source="{Binding Image_s}" Stretch="UniformToFill"/>
ViewModel:
public class ViewModel : INotifyPropertyChanged
{
private BitmapSource img;
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChanged(string propName)
{
if (this.PropertyChanged != null)
this.PropertyChanged(this, new PropertyChangedEventArgs(propName));
}
public BitmapSource Image_s
{
get { return this.img; }
set
{
this.img = value;
this.NotifyPropertyChanged("Image_s");
}
}
Window code:
viewModel = new ViewModel();
this.DataContext = viewModel;
ViewModel:
private void m_worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
BitmapSource image = (BitmapSource)e.UserState;
this.Dispatcher.Invoke(DispatcherPriority.Render,
(ThreadStart)delegate ()
{
viewModel.Image_s = image;
}
);
}

Related

Emgu.cv binding failure in WPF

I'm trying to capture video from camera and display in c# WPF form. But image dont show up when i start the program. Also debugger gives me no exception it's just running. I m debugging and i see the CapturedImage property is taking the data as supposed to be. It might be they work in the different threads. But i cant figure out. So, HELP ME,
I'm binding a ImageSource type property. As you can see,
public class VideoCapturing : INotifyPropertyChanged
{
private ImageSource capturedImage;
public ImageSource CapturedImage
{
get { return capturedImage; }
set { capturedImage = value; OnPropertyChanged("CapturedImage"); }
}
Also capturing code is here,
public void run()
{
if (cap.capture == null)
{
capture = new Emgu.CV.VideoCapture(0);
CurrentFrame = new Mat();
}
capture.ImageGrabbed += VideoCapture_ImageGrabbed;
capture.Start();
}
private void VideoCapture_ImageGrabbed(object sender, EventArgs e) // runs in worker thread
{
capture.Retrieve(CurrentFrame);
CapturedImage = ImageSourceFromBitmap(CurrentFrame.ToImage<Emgu.CV.Structure.Bgr, byte>().ToBitmap());
}
} // VideoCapturing class ends.
here is the xaml part for binding,
<Grid>
<Image x:Name="img" Source="{Binding CapturedImage}"></Image>
</Grid>
This is the mainwindow.xaml.cs,
public MainWindow()
{
InitializeComponent();
VideoCapturing VideoCapture = new VideoCapturing();
this.DataContext = VideoCapture ;
VideoCapture.run();
}
There is a typo when you call OnPropertyChanged(). "CaptureImage" but it should be "CapturedImage".
public ImageSource CapturedImage
{
get { return capturedImage; }
set { capturedImage = value; OnPropertyChanged("CapturedImage"); }
}
In MainWindow you should call VideoCapture.run() instead of capture.run().
Because of VideoCapture_ImageGrabbed runs in worker thread you have set CapturedImage on UI thread by calling Dispatcher.BeginInvoke.
private void VideoCapture_ImageGrabbed(object sender, EventArgs e)
{
capture.Retrieve(CurrentFrame);
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
CapturedImage = ImageSourceFromBitmap(CurrentFrame.ToImage<Emgu.CV.Structure.Bgr, byte>().ToBitmap());
}));
}

Binding a wpf xaml image to System.Windows.Controls.Image is not working

I have an image in wpf application and bind its Source property to System.Windows.Controls.Image in view model but it is not working. But when i bind its Source property to a BitmapImage, it is working. Is there any way to bind Source property as System.Windows.Controls.Image ?
Xaml Part
<Image x:Name="ShipMainImage" Source="{Binding MainImageSource}" />
View model Part
public class StabilityVM : INotifyPropertyChanged {
private System.Windows.Controls.Image mainImageSource;
public System.Windows.Controls.Image MainImageSource
{
get { return mainImageSource; }
set {
mainImageSource = value;
OnPropertyChanged(nameof(MainImageSource)); }
}
protected virtual void OnPropertyChanged(string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public event PropertyChangedEventHandler PropertyChanged;
}
Do not use System.Windows.Controls.Image as type of that property. It is a UI element type that is used in a view, but not in a view model.
Declare the property as System.Windows.Media.ImageSource - the type of the Source property of the Image element:
private ImageSource mainImageSource;
public ImageSource MainImageSource
{
get { return mainImageSource; }
set
{
mainImageSource = value;
OnPropertyChanged(nameof(MainImageSource));
}
}

How to save WPF textbox value to variable

Im trying to make a WPF based program that will read the textbox input (user input) from a usercontrol and save it as a object proprety. The usercontrol is added to MainWindow. From MainWindow, you have a button which displays a message box with the textbox value. I'm not sure how to connect it all.
Error = CS0103 The name 'minJpValue' does not exist in the current
context WpfApp1
Please help
(Usercontrol .xaml code)
<TextBox x:Name="minJpValue"/>
(Custom class)
public class jpData
{
public double minJpValue
{
get { return minJpValue; }
set { minJpValue = value; }
}
}
(MainWindow .cs code)
private void clickclick(object sender, RoutedEventArgs e)
{
MessageBox.Show(minJpValue);
}
The issue can be easily fixed using the MVVM Patterns,
The code for the usercontrol will be similar to this
<Grid Background="Red">
<TextBox x:Name="minJpValue" Text="{Binding Path=minJpValue}" />
</Grid>
Create new ViewModel for the MainWindow as follows
public class MainWindowViewModel : INotifyPropertyChanged
{
/// <summary>
/// Property Changed Event Handler
/// </summary>
public event PropertyChangedEventHandler PropertyChanged;
// Create the OnPropertyChanged method to raise the event
protected void OnPropertyChanged(string name)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
private String _minJpValue;
public String minJpValue {
get { return _minJpValue; }
set {
_minJpValue = value;
OnPropertyChanged(nameof(minJpValue));
}
}
}
Add the usercontrol into your MainWindow view and in the codebehind set the datacontext to the ViewModel as follows
public MainWindowViewModel CurrentModel = new MainWindowViewModel();
public MainWindow()
{
InitializeComponent();
this.DataContext = CurrentModel;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show(CurrentModel.minJpValue);
}
This can solve your current problem. Please see that its working as per expected.
For this quick fix use:
MessageBox.Show(minJpValue.Text);
But a better way would be to store the value on a VM (View Model) and bind the control to it using the MVVM pattern. I provide a basic example on
Xaml: ViewModel Main Page Instantiation and Loading Strategy for Easier Binding
Ok let's Understand wt have u done wrong.
<TextBox Name="minJpValue"/>
This line of will Create an object for TextBox and the object will be referred with ur name
minJpValue as u mentioned this will be inside another Usercontrol object and u r try to minJpValue in MainWindow how does it even know that something like minJpValue this exists
So Here is the answer:
objjpData.minJpValue = minJpValue.Text;//Inside user control when ever u change the `minJpValue` u need to set it too bjjpData.minJpValue
pass this objjpData to mainwindow or where u wanna acesses then
MessageBox.Show(objjpData.minJpValue);
Option 2:
MessageBox.Show(UserControlObject.minJpValue.Text);
And PS: Check MVVM once

Image Binding Not Working on Reload Window

I have an Image element that's bound to an ImageSource element inside a class that I've created. The ImageSource gets updated every time a slider is changed. When I first instantiate my window, the ImageSource is blank until the user loads a file. Once the file is loaded, the image appears and the user can scroll the slider and see the image change. They can then select "OK" on the dialog to save this pattern. This all works fine.
However, if they double-click on the item in the ListView then it will re-open this dialog to make further edits. So, it creates a new dialog and then reloads the pertinent info about the image. However, for whatever reason... the image binding no longer works. I can put a breakpoint on the ImageSource getter and everytime I change the slider, the image does get updated... However, it just doesn't appear the be binding correctly. Why would it bind correctly on the first time the window is opened, but not on subsequent openings. I'll try to lay out my code.
In my .XAML code:
<UserControl x:Class="MyControls.CreatePattern"
x:Name="PatternCreation"
...
d:DesignHeight="160" d:DesignWidth="350">
<Slider Value="{Binding ElementName=PatternCreation, Path=Pattern.ZNorm, Mode=TwoWay}" Maximum="1" Name="Slider" VerticalAlignment="Stretch" />
<Image Name="PatternPreview" Source="{Binding ElementName=PatternCreation, Path=Pattern.WPFSlice}" Stretch="Uniform"></Image>
</UserControl
In my code behind I define the Pattern to be bound:
protected PatternVoxelBased mPattern = new PatternVoxelBased();
public PatternVoxelBased Pattern
{
get { return mPattern ; }
set { mPattern = value; }
}
In my PatternVoxelBased class, I have a WPFSlice and ZNorm properties defined like this:
protected ImageSource mWPFSlice;
public ImageSource WPFSlice
{
get { return mWPFSlice; }
set
{
mWPFSlice = value;
NotifyPropertyChanged("WPFSlice");
}
}
protected double mZNorm = 0.5;
public double ZNorm
{
get { return mZNorm; }
set
{
if (mZNorm == value) return;
mZNorm = value;
NotifyPropertyChanged("ZNorm");
WPFSlice = BuildImageAtZ(mZNorm);
}
}
I have an event to load the dialog window the first time:
private void CreatePattern_Click(object sender, RoutedEventArgs e)
{
CCreateVoxelPattern dlg = new CCreateVoxelPattern();
dlg.DataContext = DataContext;
dlg.CShow(PatternLibraryMenu);
}
My ListView Double-Click function to reload the dialog window:
private void ListViewPatternLibrary_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
PatternVoxelBased item = ((ListView)sender).SelectedValue as PatternVoxelBased;
CCreateVoxelPattern dlg = new CCreateVoxelPattern();
dlg.DataContext = DataContext;
dlg.Main.Pattern = item;
dlg.Main.LoadPattern();
dlg.CShow(PatternLibraryMenu);
}
public void LoadPattern()
{
if (Pattern == null) return;
Pattern.WPFSlice = Pattern.BuildImageAtZ(Pattern.ZNorm);
}
In your class where this is
protected PatternVoxelBased mPattern = new PatternVoxelBased();
public PatternVoxelBased Pattern
{
get { return mPattern ; }
set { mPattern = value; }
}
you have to implement INotifyPropertyChanged.
Example
public class YourClass: INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(PropertyChangedEventArgs e)
{
if (PropertyChanged != null)
{
PropertyChanged(this, e);
}
}
protected PatternVoxelBased mPattern = new PatternVoxelBased();
public PatternVoxelBased Pattern
{
get { return mPattern ; }
set { mPattern = value; OnPropertyChanged(new PropertyChangedEventArgs("Pattern"));}
}
}
EDIT
In your Pattern-class, you have to implement that too on every Property.

WPF image binding and INotifyPropertyChanged, issue with image display

I am trying to bind an image in a wpf application. I am using vs2010.
I am pasting code below and explain what I have done, what works and what doesn't.
XAML code:
<Image Name="newImage" ImageFailed="newImage_ImageFailed" HorizontalAlignment="Right" Width="auto" Height="auto" Margin="5" Source="{Binding imgSource}">
C# code:
public MainWindow()
{
InitializeComponent();
arraytoImage atim = new arraytoImage();
newImage.DataContext = atim;
}
Code below is in different namespace, where arraytoImage class is implemented. This class takes a cuda array, creates a bitmap and then converts it in into a bitmapimage using memorystream. For now, I am setting a random color to all the pixels, just to see if that binding works. But it doesn't. Below I have pasted a code that displays the image.
I am sure that bitmapimage is correctly created. I think the issue is incorrect binding.
class arraytoImage : INotifyPropertyChanged
{
// displays images (focused files)
private BitmapImage bitmapImage = new BitmapImage();
private BitmapImage testim = new BitmapImage();
public BitmapImage arraytoImageCon(cuFloatComplex[] dataIn, int wid, int ht)
{
//code that generates bitmapimage
}
public BitmapImage imgSource
{
get { return testim1; }
set
{
if (testim1 != value)
{
testim1 = value;
OnPropertyChanged("imgSource");
}
}
}
#region INotifyPropertyChanged implementation
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
}
Edit: calling arrayToImageCon:
public class ReadRawFiles
{
//Tons of code
public void focusdata()
{
//tons of code
arraytoImage atoi = new arraytoImage();
BitmapImage tmp= atoi.arraytoImageCon(datafft_azi, nazimuth,nrange);
atoi.imgSource=tmp;
}
}
My question is, what am I doing wrong.
Thanks a lot in advance. Kindly ask further details if I missed something.
Regards
binding is set to one instance. I was making multiple instances.

Categories

Resources