uwp image binding not working with x:Bind - c#

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!

Related

UWP, my app crashes for the image path when built , but when I run it on the debugger it works fine

I'm creating a UWP that receives the image path from a static class. It works fine when I'm debugging it, but when built, the application crashes.
I have tried with a lot of different ways of accessing the image path from code behind (Uri, BitmapImage, etc.) which has been defined by the selected object. Below, you can see the code that has allowed me to do it. The try and catch was a way for me to notice if that was what had been crashing the application.
try
{
ImageSource result = new BitmapImage(new Uri("ms-appx:///" +
EntriesDone.SelectedEntry.ImagePath));
img_entry.Source = result;
img_entry.Opacity = 0.40;
img_entry.MaxWidth = 500;
img_entry.MaxHeight = 500;
}
catch (Exception)
{
txt_Name.FontSize=2;
}
What I would like to know is if there is a better way for me to access the image path or the assets folder allowing the object to define the image that will be shown (there are more than 60 entries so I need to do it efficiently) and that won't crash the application upon being built. I'd also like to know why this crashes the application when built. Thanks!
What I would like to know is if there is a better way for me to access the image path or the assets folder allowing the object to define the image that will be shown
For your requirement, you can use DataTemplate and ListView (or GridView) to show the images.
create data model:
public class ImageModel
{
public string ImageUrl { get; set; }
// Other properties
...
}
In the code-behind file of the page, create a new collection and fill the data:
// ObservableCollection can notify UI when collection item changed
public ObservableCollection<ImageModel> ImageCollection = new ObservableCollection<ImageModel>();
public TestImagePage()
{
this.InitializeComponent();
ImageInit();
}
public void ImageInit()
{
// Load image model here.
// e.g.
ImageCollection.Add(new ImageModel{ImageUrl="ms-appx:///Assets/image.png"});
}
Create DataTemplate and GridView on XAML:
<Page
...>
<Grid>
<GridView ItemsSource="{x:Bind ImageCollection}">
<GridView.ItemTemplate>
<DataTemplate x:DataType="local:ImageModel">
<Image Opacity="0.4"
MaxWidth="500"
MaxHeight="500"
Source="{x:Bind ImageUrl}"
/>
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
</Grid>
</Page>
The process I provide is very simple, you can expand this code according to your needs.
Best regards.

ImageBox insert image without path

I would like to add the image directly to the image box, so imgVarschaubild.Source = sa;
Unfortunately this does not work, how do I do it? Without which I have to save the picture first but must directly insert the picture?
My solution at the moment:
System.Drawing.Image sa;
....
if (saveFileDialog.ShowDialog() == true)
{
sa.Save(saveFileDialog.FileName);
MessageBox.Show(saveFileDialog.FileName);
ImageSource imageSource = new BitmapImage(new Uri(saveFileDialog.FileName));
imgVorschaubild.Source = imageSource;
}
System.Drawing.Image is a Windows Form class. You could try to convert it to a BitmapSource using any of the suggestions and code samples from here:
Show Drawing.Image in WPF
Once you have done that you could set the Source property of the Image element to the BitmapSource:
imgVorschaubild.Source = GetImageStream(sa);
It seem's like you are not using the MVVM pattern. I hardly recommend it.
If you use it you could easily bind your imagePath to an Image.
You just need a string property in your ViewModel and bind to it in your View like
<Image Source="{Binding ImagePath}" />

Hub control Background sometimes not drawn or drawn incorrectly

I have a Windows Phone 8.1 (WinRT) app that has a Page and on that page there is a Hub control. My intention is to set an image as the background of the Hub because I like the cool animation when swiping through the HubSections.
I do this with the following XAML:
<Hub>
<Hub.Background>
<ImageBrush
ImageSource="{Binding Images.Fanart}"
Stretch="UniformToFill"
Opacity="0.3">
</ImageBrush>
</Hub.Background>
<!-- here come some hub sections with content -->
</Hub>
As you can see, the Background is set to be an ImageBrush. This brush has the ImageSource property bound to Images.Fanart, which is an ImageSource class in my data model:
public Images
{
private ImageSource _fanart;
public ImageSource Fanart
{
get { return _fanart; }
private set
{
if (_fanart != value)
{
_fanart = value;
NotifyPropertyChanged(); // Note: notification works properly
}
}
}
}
Now, my intention is to download images from the web and set them as the Fanart:
Fanart = new BitmapImage(new Uri("{the_image_url}", UriKind.Absolute));
This downloading and setting is done when the page is navigated to (OnNavigatedTo event).
Now the actual problem:
Sometimes this works properly and the image is loaded and behaves/animates correctly when swiping through the hub sections.
However, sometimes the image does not show up at all, although debugging reveals that the Fanart property has been refreshed.
And sometimes, the image is shown, but it is animated in a wrong way. It is not drawn in its full width and it seems that its left margin is not mapped to the left margin of the first hub section.
This is pretty annoying and I wonder what I'm doing wrong. Maybe this is also a bug in the Hub Control?

Getting a dynamic Image through event in WPF

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

Using WPF how to use Binding to Grayscale an Image on some condition

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();
}
}
}

Categories

Resources