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.
Related
The following is part of my View in which I have bound an Image to a property in my ViewModel:
<Image Source="{Binding Image}" Grid.Column="2" Grid.ColumnSpan="2"/>
My ViewModel is this:
public class MainWindowViewModel : INotifyPropertyChanged
{
public BitmapImage Image
{
get { return _image; }
set
{
_image = value;
OnPropertyChanged();
}
}
Action _makeScannerAlwaysOnAction;
private BitmapImage _image;
public MainWindowViewModel()
{
AddNewPersonCommand = new RelayCommand(OpenFrmAddNewPerson);
FingerPrintScannerDevice.FingerPrintScanner.Init();
MakeScannerAlwaysOn(null);
}
private void MakeScannerAlwaysOn(object obj)
{
_makeScannerAlwaysOnAction = MakeScannerOn;
_makeScannerAlwaysOnAction.BeginInvoke(Callback, null);
}
private void Callback(IAsyncResult ar)
{
FingerPrintScannerDevice.FingerPrintScanner.UnInit();
var objFingerPrintVerifier = new FingerPrintVerifier();
objFingerPrintVerifier.StartVerifingProcess();
var ms = new MemoryStream();
ms.Position = 0;
objFingerPrintVerifier.MatchPerson.Picture.Save(ms, ImageFormat.Png);
var bi = new BitmapImage();
bi.BeginInit();
bi.StreamSource = ms;
bi.EndInit();
Thread.Sleep(2000);
Dispatcher.CurrentDispatcher.Invoke(() => Image = bi);
//Image = bi;
_makeScannerAlwaysOnAction.BeginInvoke(Callback, null);
}
private void MakeScannerOn()
{
while (true)
{
if (FingerPrintScannerDevice.FingerPrintScanner.ScannerManager.Scanners[0].IsFingerOn)
{
return;
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
var handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
My Problem:
The problem is when I want to bind the Image it gives me the error
Must create DependencySource on same Thread as the DependencyObject
I have googled a lot and I have seen the post in SO but neither of them worked for me.
any kind of help would be very appreciated.
BitmapImage is DependencyObject so it does matter on which thread it has been created because you cannot access DependencyProperty of an object created on another thread unless it's a Freezable object and you can Freeze it.
Makes the current object unmodifiable and sets its IsFrozen property to true.
What you need to do is call Freeze before you update Image:
bi.BeginInit();
bi.StreamSource = ms;
bi.EndInit();
bi.Freeze();
Dispatcher.CurrentDispatcher.Invoke(() => Image = bi);
as pointed out by #AwkwardCoder here is Freezable Objects Overview
While bi.Freeze(); worked for me in one case, I've seen no difference from adding/removing
Dispatcher.CurrentDispatcher.Invoke(() => Image = bi);
The second time I used DataTemplate in xaml and all the same classes as in the first case, but I kept getting the same Error.
This was a thing that helped:
Application.Current.Dispatcher.Invoke(() => Image = bi);
Maybe accepted answer can be improved because Dispatcher.CurrentDispatcher don't actually give you UI thread.
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));
}
}
I have a C# UWP solution for myself and I have defined the special manifest broadFileSystemAccess, so I can access all files from my PC directly.
I fill a ListView by setting the ItemsSource of the ListView to a ObservableCollection<someModel> variable (more details below). After tapping on it, I want to change it.
In class someModel I set the path to the image and the content as BitmapImage. I do this because, the file is on some path on my PC, e.g. E:\pix\some path\image.jpg, then read this file into the BitmapImage, so I can later bind it as the Image source. This is super slow and inefficient, but it works for now and I'll change it in the future.
class someModel
{
public string ImagePath { get; set; }
public BitmapImage ImageContent { get; set; }
}
and my XAML image:
<Image DataContext="{x:Bind Mode=TwoWay}" Source="{x:Bind ImageContent, Mode=OneWay}" Width="400" Stretch="UniformToFill" Tapped="lvImageEditImage_Tapped" />
my function lvImageEditImage_Tapped :
var picker = new Windows.Storage.Pickers.FileOpenPicker
{
ViewMode = Windows.Storage.Pickers.PickerViewMode.Thumbnail,
SuggestedStartLocation = Windows.Storage.Pickers.PickerLocationId.PicturesLibrary
};
StorageFile file = await picker.PickSingleFileAsync();
if (file != null)
{
var item = (sender as Image).DataContext as someModel;
item.ImagePath = file.Path;
BitmapImage bitmapImage = new BitmapImage();
using (IRandomAccessStream fileStream = await file.OpenAsync(FileAccessMode.Read))
{
await bitmapImage.SetSourceAsync(fileStream);
}
item.ImageContent = bitmapImage;
}
While I now get the path, the image content bitmapImage doesn't change the viewed image.
Why doesn't the image update to the new BitmapImage content?
Please add the INotifyPropertyChanged interface to the data model.
public class someModel:INotifyPropertyChanged
{
private BitmapImage _imageContent;
public BitmapImage ImageContent
{
get => _imageContent;
set
{
_imageContent = value;
OnPropertyChanged();
}
}
public string ImagePath { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged([CallerMemberName]string propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
After inheriting the INotifyPropertyChanged interface, you can use {x:Bind ImageContent, Mode=OneWay} to complete the binding. When the data source is modified, the UI interface will be notified to change.
Best regards.
I have ViewModel that makes some functions. Funcs are initiate by button, i have command on button click.
ViewModel.cs
class WindowViewModel : INotifyPropertyChanged
{
public WindowViewModel()
{
canExecute = true;
}
public ICommand ApplyKMMCommand //command for button click, works great, tested
{
get
{
return applyKMMCommand ?? (applyKMMCommand = new Commands.CommandHandler(() =>
ApplyKMMToNewImage(), canExecute));
}
}
private bool canExecute;
private ICommand applyKMMCommand;
public void ApplyKMMToNewImage()
{
ApplyKMM.Init(); //algorithm name
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public BitmapImage DisplayedImage //displaying image that i work with
{
get { return Bitmaps.Filepath; }
set { Bitmaps.Filepath = value; NotifyPropertyChanged(nameof(DisplayedImage)); }
}
}
Now, my ApplyKMM.Init()
class ApplyKMM
{
public static void Init()
{
Bitmaps.Filepath = //do some thing with it...
}
}
And my Models.Bitmaps.cs
static public BitmapImage Filepath
{
get { return filepath; }
set { filepath = value; }
}
static private BitmapImage filepath{ get; set; }
The problem is, when i make ApplyKMM.Init the Image control that is binded to View not change their value.
Without ApplyKMM i can do in ViewModel that thing:
DisplayedImage = //do things with bitmap...
And then, Image that is presented in View change (after making things with that image).
Can you tell me, how to notify ViewModel, that somewhere in code filepath from Models changed?
EDIT:
Binding in View Looks like standard binding:
<Image Source="{Binding DisplayedImage}"/>
Button click works too, i have problem only with communication between Models->ApplyKMM->ViewModel
EDIT2:
Properties Filepath is storage in Models folder, not folder where function ApplyKMM is. Look into my edit, i try to make something like:
Models -> ApplyKMM -> ViewModel. From Models, i get Filepath. Then, i using function ApplyKMM that is in another namespace. Then, after working on bitmap with ApplyKMM func i want to somehow notify ViewModel, that work on Model is done (for example, convert to grayscale) and i want to show that grayscale image in VM. It works, when i want to do Model -> ViewModel (ApplyKMM is in VM class) but i want to move out ApplyKMM away from ViewModel. And that when staris starts for me.
It appears like you want to notify when a static property changes. For this, you may use the StaticPropertyChanged event.
class ApplyKMM
{
#region Properties
static BitmapImage _Filepath;
public static BitmapImage Filepath
{
get { return _Filepath; }
set { if (_Filepath != value) { _Filepath = value; NotifyPropertyChanged(nameof(Filepath)); } }
}
#endregion
#region Static NotifyPropertyChanged
public static void NotifyStaticPropertyChanged(string propertyName)
{
StaticPropertyChanged?.Invoke(null, new PropertyChangedEventArgs(propertyName));
}
public void NotifyAllStaticPropertyChanged()
{
NotifyStaticPropertyChanged(string.Empty);
}
public static event EventHandler<PropertyChangedEventArgs> StaticPropertyChanged;
#endregion
}
Please take note that this is available from WPF Version 4.5.
You might also find this question interesting.
Basically it is not a good practice to notify changes of a static variable to an instance.
Then, let’s look at your code:
Bitmaps class does not implement INotifyPropertyChanged, so when Filepath changes, nothing will be notified (of course, it is a static property)
In your case, you should use local variable to hold DisplayedImages. Then changes on DisplayedImage should be updated by the binding.
BitmapImage _displayedImage;
public BitmapImage DisplayedImage
{
get { return displayedImage; }
set { displayedImage = value; NotifyPropertyChanged(nameof(DisplayedImage)); }
}
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;
}
);
}