I'm trying to add a dynamic Image in my WPF form. I've added the Image like this:
<Image Height="212" HorizontalAlignment="Left" Margin="12,167,0,0"
Name="picture_scan" Stretch="Fill" VerticalAlignment="Top" Width="227"
Source="{Binding FingerprintSource}" />
The source leads to the following code in my service class:
public BitmapSource FingerprintSource
{
get { return fingerprintScan.WpfImageSource; }
}
The WpfImageSource is a BitmapSource. As I said, the Image is dynamic. Through an event from my Fingerprint Reader, the following code is called:
private void HandleFingerprintObtainedEvent(Fingerprint fingerprint, FingerprintImage fingerprintImage)
{
Debug.WriteLine("New fingerprint found!");
fingerprintScan = fingerprintImage;
}
When I run the program and press my finger on the reader, a new fingerprint image is found. The value fingerprintScan is being changed. But the problem is, before and after putting my finger on the scanner, the bitmap is empty (white?). What am I doing wrong? Do I need to do more besides databinding, like checking for events or something? Is it a problem when the source of the databinding is a BitmapSource instead of a BitmapImage?
You are not notifying that the property has changed.
The class that has de FingerprintSource property has to implement the interface INotifyPropertyChanged. Then you can use the property setter to raise the PropertyChanged event. Otherwise the WPF binding does not know that something has changed.
Here you have a good start point: WPF/MVVM Quick Start Tutorial
Related
I am trying to bind an imageSource within an ellipse on my XAML page to an ImageSource property in my ViewModel, as I am using MVVM approach in my project. I can confirm by breakpoints that the property in c# gets the image and gets filled, but for some odd reason it doesn't show up in XAML, and when I analyze source property with livepropertyExplorer in the blend, the source in ImageSource shows "0". Here is my code.
XAML
<Ellipse x:Name="ProfileImage" Style="{StaticResource ProfilePicStyle}">
<Ellipse.Fill>
<ImageBrush ImageSource="{x:Bind ViewModel.Banner, Mode=OneWay}"
Stretch="UniformToFill"/>
</Ellipse.Fill>
</Ellipse>
ViewModel
public AllVideosViewModel() : base()
{
//var bit = new BitmapImage();
//bit.UriSource = (new Uri("ms-appx:///Assets/Storelogo.png"));
//Banner = bit;
//Above 3 lines were test code and it works perfect and binding works in this case, but I want the binding as coded in the Initialize method below, because I want that image to bind with the thumbnails of the collection.
Initialize();
}
private async void Initialize()
{
var VideoFiles = (await KnownFolders.VideosLibrary.GetFilesAsync(CommonFileQuery.OrderByName)) as IEnumerable<StorageFile>;
foreach (var file in VideoFiles)
{
<...some code to fill grid view on the same XAML page which works perfect...>
Banner = await FileHelper.GetDisplay(file);//this method returns Image just fine because I am using the same method to display thumbnails on the same XAML page which work fine.
}
}
Thanks in advance.
UPDATE Sample project
sample project to test on github
A few things I have noticed in your code.
Your MainViewModel needs to implement INotifyPropertyChanged and your Banner property needs to raise the property changed event. This is why you don't see any image displayed on the UI.
You should use await bit.SetSourceAsync() instead of bit.SetSourceAsync() as it doesn't block the UI thread.
Since you are not using the Image control but the ImageBrush directly, you should set the decode size to how much you need so you don't waste memory there. Note the Image control does this for you automatically.
bit = new BitmapImage
{
DecodePixelWidth = 48,
DecodePixelHeight = 48
};
Hope this helps!
In my code, I have an UIElement variable I set with certain button presses.
Now, I have this variable:
public UIElement currentMenu;
Set to this value:
currentMenu = (UIElement)Resources["Home"];
I get it from the Resources so I don't have to manage it messily in the code-behind, I will export the Resources to a seperate ResourceDictionary once I get this problem solved.
My SplitView looks like this:
<SplitView x:Name="NavPane" OpenPaneLength="250" CompactPaneLength="50" Content="{x:Bind currentMenu}" DisplayMode="CompactOverlay" IsPaneOpen="False" PaneClosing="NavPane_PaneClosing">
The prblem comes in at this point, the Binding crashes the entire application with an unhndled win32 exception. I get no description and the error code changes every time. I have checked with break points whether this behaviour is actually caused by the binding, and it is.
If you have any suggestions on what might be going wrong here, please post an answer. I will supply any additional information needed (if reasonable, I'm not going to send you my entire project files)
Any help is appreciated!
Your problem that you are using a variable, not a property.
private UIElement currentMenu;
public string CurrentMenu
{
get { return currentMenu; }
set {
currentMenu=value);
OnPropertyChanged("CurrentMenu");
}
}
So the basic rules to bind Control to a "varaible":
Variable should be a property, not a field.
it should be public.
Either a notifying property (suitable for model classes) or a dependency property (suitable for view classes)
To notify UI you should implement INotifyPropertyChanged:
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
Update:
Your Bidning should looks like:
<SplitView x:Name="NavPane" OpenPaneLength="250" CompactPaneLength="50"
Content="{Binding CurrentMenu}" DisplayMode="CompactOverlay" IsPaneOpen="False"
PaneClosing="NavPane_PaneClosing">
I have found the answer to my question!
Namely, this was not the way to do it. Instead, I declared a Frame inside the Content of the SplitView:
<SplitView.Content>
<Frame x:Name="activeMenu"/>
</SplitView.Content>
Then, I use the Frame.Navigate() function to load my menus into the Frame:
public MainPage()
{
DataContext = this;
this.InitializeComponent();
SetMenu(0);
}
private void SetMenu(int key)
{
switch (key)
{
case 0:
activeMenu.Navigate(typeof(HomeMenu));
break;
//You can add in as many cases as you need
}
}
What you then need is to set all the menus you want as separate Pages within your project files. in this example, HomeMenu.xaml contains the grid for the menu people see upon starting up the app.
This solved the problem, but thank you to everyone (StepUp) who contributed to the original (unfortunately unsuccessful) solution!
Background:
I have an application that has list of CheckBoxes and Button.
If the user selects a (or multiple) CheckBox and Click on the button, the Button event handler checks which CheckBox is checked. Based on that, it runs a process (ie. gpupate).
Then, I have an image (Visibility = "hidden") next to CheckBox in XAML. After the button is clicked, the code behind sets it to Visibility.Visible.
After the process is done, the Source of the image is changed to a different image. Bascically, the first image shows the process is running, second image is a check showing its completed.
I am trying to implement INotifyPropertyChanged Interface, so the UI is updated automatically after I change the visibility. Sometimes, UI is not updated after the the visibility is changed because there are number of CheckBoxes.
However, since I am not using any property, I cannot really bind it to something (or may be I am missing something) and INPC interface.
How can I implement the interface (or similar functionality).
XAML Code
<StackPanel Orientation="Horizontal">
<Image x:Name="oneImage"
Source="{StaticResource inProcessImage}"
Visibility="Hidden" />
<CheckBox x:Name="oneCheckBox"
Content="CheckBox"
Style="{StaticResource normalCheckBox}"/>
</StackPanel>
Code Behind inside Button Event Handler
if (oneCheckBox.IsChecked ?? false)
{
oneImage.Visibility = Visibility.Visible;
await Task.Run(() =>
{
//run GPUpdate
});
deleteHistoryImage.Source = (ImageSource)Resources["doneCheckImage"];
}
I do not have anything regarding the implementation of interface because I do not know what do I need to bind Visibility modifier with.
This is not what you're looking for, but it will update the GUI manually.
public void UpdateUI()
{
Application.Current.Dispatcher.Invoke(DispatcherPriority.Background, new ThreadStart(delegate { }));
}
call UpdateUI(); after you change the visibility.
The application ia a messenger in which I am using microsoft lync client for this purpose. In one of the context I am getting the contacts (which is an object of LyncClient having properties like name, image , Availability, etc) in a listview and loading them in a data template which is defined as follow:
<DataTemplate x:Key="ContactsTemplate">
<Grid HorizontalAlignment="Left" Width="150" Height="150" Margin="10">
<Border Background="{StaticResource ListViewItemPlaceholderBackgroundThemeBrush}">
<Image Source="{Binding Image}" Stretch="UniformToFill" AutomationProperties.Name="{Binding Title}"/>
</Border>
<StackPanel VerticalAlignment="Bottom" Background="{Binding Availability, Converter={StaticResource AvailabilityToPresenceColor}}" Opacity="0.75">
<TextBlock Text="{Binding Name}" Foreground="{StaticResource ListViewItemOverlayForegroundThemeBrush}" Style="{StaticResource TitleTextStyle}" Height="20" Margin="15,0,15,15"/>
</StackPanel>
</Grid>
</DataTemplate>
It has Grid container in which we have an image and textblock controls which show the image and name of the contact and as its shown below the background of stackpanel is binded to Availability property of lync Contact object with a converter which map the availibility status to a color so that for example the background of stackpanel will turn red when the contact availibility is busy.
I want to have similar effect for the image control as well.
I am new to binding so totaly lost in this bindig concept.
My idea was: there is a effect evend handler for image so i thought of using that for this purpose and use
and inside the converter under some condition I want to use some code in which i need to get the image source, but as we are getting the image source through binding
please suggest me your ideas.
Well as u can see in the code
<Image Source="{Binding Image}" Stretch="UniformToFill" AutomationProperties.Name="{Binding Title} effect="{Binding Availability, Converter={StaticResource AvailabilityToPresenceColor}}"/>
I am just binding source of image control with a property of Contact object. I want to send the Availability properties of a Contact object to Convert method of IValueConverter or I want to bind the image with the whole Contact Object if it is possible...or if some other way please let me know.
#####################comment attachment
var bitmap = new BitmapImage();
bitmap.BeginInit();
MemoreyStream ms=new MemoryStream(_image);
bitmap.StreamSource = stream;
bitmap.CacheOption = BitmapCacheOption.OnLoad;
bitmap.EndInit();
var grayBitmapSource = new FormatConvertedBitmap();
grayBitmapSource.BeginInit();
grayBitmapSource.Source = ms;
grayBitmapSource.DestinationFormat = PixelFormats.Gray32Float;
grayBitmapSource.EndInit();
.....
now the thing is i have grayBitmapSource which is of type FormatConvertedBitmap and i dont know how to convert it to Stream again.
I would suggest looking at this article about image processing in WPF: http://www.codeproject.com/Articles/237226/Image-Processing-is-done-using-WPF
Using the image processing logic, you create the different pictures for each availability status. You could use an IValueConverter, but that means you have to reprocess the image each time the availability status changes. Instead, you can simply change your Contact class so that when you change the Availability property, it automatically signals WPF to get the picture referenced by the Image property:
public class Contact : INotifyPropertyChanged
{
// EDIT: INotifyPropertyChanged implementation.
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChanged(String propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
// EDIT: INotifyPropertyChanged implementation.
private ContactAvailability _Availability;
public ContactAvailability Availability
{
get { return _Availability; }
set
{
_Availability = value;
NotifyPropertyChanged("Availability");
NotifyPropertyChanged("Image");
}
}
public BitmapImage _AvailablePicture;
public BitmapImage _BusyPicture;
public BitmapImage Image
{
get
{
switch (this.Availability)
{
case ContactAvailability.Available:
return this._AvailablePicture;
case ContactAvailability.Busy:
return this._BusyPicture;
default:
throw new NotImplementedException();
}
}
}
}
EDIT (too long for comment):
I added the code to implement the INotifyPropertyChanged interface. This is very common in WPF so I thought you were familiar with this approach already.
In your example, Image.Source is a DepencyProperty. When a class implements INotifyPropertyChanged, you can tell WPF that one of its properties has changed. You simply raise the NotifyPropertyChanged event with the name of the property that changed. This signals WPF to update all DepencyPropertys that bind to the given property.
how is this different with binding in term of image processing. I mean every time the availibility changes then in this way also the image processing code should be execute as well. am I right or not #bouvierr?
No. In this case, we would only execute the image processing a fixed number of times to create the picture for each availability status (2 times for each contact in my example). For example, we could create all pictures during application startup (3 contact x 2 status = 6 pictures) and store them in each contact's _AvailablePicture and _BusyPicture fields.
Here is the IMPORTANT part: when we SET the Availability property, we also call NotifyPropertyChanged("Image"). This will force WPF to update the Image.Source DepencyProperty because it binds to Contact.Image. This will return a different picture, because the Availability has changed.
In my example, I decided to store the pictures. This might not be the best solution for you. It consumes more memory, but saves processing time. If you prefer to re-process images each time the Availability status changes, you should change the Contact.Image property to something like:
public BitmapImage Image
{
get
{
switch (this.Availability)
{
case ContactAvailability.Available:
return this._AvailablePicture;
case ContactAvailability.Busy:
return GetImageWithColorFilter(this._AvailablePicture, Colors.Red);
default:
throw new NotImplementedException();
}
}
}
Can anyone shed some light as to why the following code is not working? By "not working" I mean the image is not rendered in the Panorama control:
XAML
DataContext="{Binding RelativeSource={RelativeSource Self}}"
shell:SystemTray.IsVisible="False">
<Grid x:Name="LayoutRoot">
<controls:Panorama Title="My Control">
<controls:Panorama.Background>
<ImageBrush ImageSource="{Binding RandomImage}"/>
</controls:Panorama.Background>
C#
public string RandomImage { get; set; }
Note: The RandomImage property is set to a public jpg image on the internet.
EDIT
I have also tried to change the RandomImage property to ImageSource but did not have any luck with that.
I'm gonna hazard a guess that you're setting RandomImage at some point after the page loads, which means that the binding has already been checked. You need to implement INotifyPropertyChanged and call your PropertyChanged event in the setter for RandomImage. For a detailed explanation of this, check out this MSDN article.
The long and short of it is that the binding is checked when the page loads and then not again unless something triggers it. Implementing INotifyPropertyChanged means that when you call your PropertyChanged event, it notifies the UI to check the binding again and see what's new so it can update itself.