4

Whenever I wanted to display an image in the past, I bound the image path to the image's source property. Too easy.

Now I want to change the image and always show the image with the latest changes. The change image is saved in a BitmapImage property inside my class. So instead of asking the image control to load the image from disc, I wanted to bind it directly to my BitmapImage property. But the image does not show.

Then (just for testing) I created a value converter, used the path to the image in there to create a BitmapImage and returned that to the control - and the image shows.

Again: Creating a BitmapImage from a path inside the coverter works. Binding the image control to a BitmapImage property that is created in my class with the same code fails.

That describes the same problem, but the "solution" doesn't work. (I wonder why it is marked as solved, since the OP made the same comment)

https://stackoverflow.com//questions/7263509/directly-binding-a-bitmapimage-created-inside-a-class-bound-to-a-listbox-in-wpf

EDIT: here is some code

This is the converter that successfully creates a visible image.

public class BsConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        BitmapImage bi = new BitmapImage(new Uri(value.ToString()));

        return bi;
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

... and the XAML binding that does show the image. File is of type FileInfo and FullName holds the complete path.

<Image MinHeight="100" MinWidth="100" Source="{Binding SelectedImage.File.FullName, Converter={StaticResource BsConverter}}"/>

I have a property BitmapImage image { get; set; } that I initialize in the constructor of my class:

image = new BitmapImage();
image.BeginInit();
image.UriSource = new Uri(file.FullName);
image.CacheOption = BitmapCacheOption.OnLoad;
image.EndInit();

...and the binding. But - no joy. The image is not displayed.

<Image MinHeight="100" MinWidth="100" Source="{Binding SelectedImage.image}"/>
Community
  • 1
  • 1
Peter
  • 249
  • 3
  • 11
  • The `image` property needs to be public. In order to update a binding when the property value changes, you need to implement the [INotifyPropertyChanged](http://msdn.microsoft.com/en-us/library/system.componentmodel.inotifypropertychanged.aspx) interface, or make `image` a dependency property. And widely accepted [coding conventions](http://msdn.microsoft.com/en-us/library/vstudio/ms229043(v=vs.110).aspx) recommend to use Pascal cased property names, hence `Image`. – Clemens Jun 01 '13 at 13:25
  • omfg. It is late, I need to go to bed. What a stupid mistake. Thank you so much! – Peter Jun 01 '13 at 13:30
  • Clemens, if you post that hint as answer, I will accept ist. – Peter Jun 01 '13 at 14:31

2 Answers2

4

The property must be public. In order to update a binding the class that defines the property must implement the INotifyPropertyChanged interface.

public class SelectedImage : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    private ImageSource image;

    public ImageSource Image
    {
        get { return image; }
        set
        {
            image = value;

            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs("Image"));
            }
        }
    }
}
Clemens
  • 123,504
  • 12
  • 155
  • 268
1

I ran into the same issue, it seems to have to do with timing and asynchronous loading of the picture. Probably the converter code is running at a different priority in the Dispatcher, so it behaves differently.

For my project, I got around this behaviour by preloading the BitmapImage explicitly in code, like

        Dim result As ScaleItImageSource = Nothing

    Dim stream As System.IO.FileStream = Nothing
    Try
        stream = New System.IO.FileStream(fileName, IO.FileMode.Open, IO.FileAccess.Read)
        Dim decoder As BitmapDecoder = System.Windows.Media.Imaging.BitmapDecoder.Create(stream, BitmapCreateOptions.None, BitmapCacheOption.OnLoad)
        If decoder.Frames.Count > 0 Then
            result = New ScaleItImageSource(decoder.Frames(0), fileName)
        End If
    Finally
        If stream IsNot Nothing Then
            stream.Close()
        End If
    End Try

    Return result
hbarck
  • 2,934
  • 13
  • 16