51

I am having some trouble binding in Image to my viewmodel. I finally got rid of the XamlParseException, but the image does not come up. I even hard coded the image in the ViewModel. Can someone see what I am doing wrong?

View:

<Image HorizontalAlignment="Left" Margin="0,0,0,0" Name="image1" Stretch="Fill" VerticalAlignment="Bottom" Grid.Row="8" Width="200"  Grid.ColumnSpan="2" >
<Image.Source>
    <BitmapImage DecodePixelWidth="200" UriSource="{Binding Path=DisplayedImage, Mode=TwoWay}" />
</Image.Source>

ViewModel:

 string _DisplayedImagePath = @"C:\Users\Public\Pictures\Sample Pictures\Chrysanthemum.jpg";//string.Empty;
    int _DisplayedImageIndex;
    BitmapImage _DisplayedImage = null;
    public BitmapImage DisplayedImage
    {
        get
        {
            _DisplayedImage = new BitmapImage();
            if (!string.IsNullOrEmpty(_DisplayedImagePath))
            {
                _Rail1DisplayedImage.BeginInit();
                _Rail1DisplayedImage.CacheOption = BitmapCacheOption.OnLoad;
                _Rail1DisplayedImage.CreateOptions = BitmapCreateOptions.IgnoreImageCache;
                _Rail1DisplayedImage.UriSource = new Uri(_DisplayedImagePath);
                _Rail1DisplayedImage.DecodePixelWidth = 200;
                _Rail1DisplayedImage.EndInit();
            }
            return _Rail1DisplayedImage;
        }
        set
        {
            _Rail1DisplayedImage = value;
            OnPropertyChanged("DisplayedImage");
        }
    }
kurgaan
  • 796
  • 1
  • 7
  • 17

3 Answers3

114

Displaying an Image in WPF is much easier than that. Try this:

<Image Source="{Binding DisplayedImagePath}" HorizontalAlignment="Left" 
    Margin="0,0,0,0" Name="image1" Stretch="Fill" VerticalAlignment="Bottom" 
    Grid.Row="8" Width="200"  Grid.ColumnSpan="2" />

And the property can just be a string:

public string DisplayedImage 
{
    get { return @"C:\Users\Public\Pictures\Sample Pictures\Chrysanthemum.jpg"; }
}

Although you really should add your images to a folder named Images in the root of your project and set their Build Action to Resource in the Properties Window in Visual Studio... you could then access them using this format:

public string DisplayedImage 
{
    get { return "/AssemblyName;component/Images/ImageName.jpg"; }
}

UPDATE >>>

As a final tip... if you ever have a problem with a control not working as expected, simply type 'WPF', the name of that control and then the word 'class' into a search engine. In this case, you would have typed 'WPF Image Class'. The top result will always be MSDN and if you click on the link, you'll find out all about that control and most pages have code examples as well.


UPDATE 2 >>>

If you followed the examples from the link to MSDN and it's not working, then your problem is not the Image control. Using the string property that I suggested, try this:

<StackPanel>
    <Image Source="{Binding DisplayedImagePath}" />
    <TextBlock Text="{Binding DisplayedImagePath}" />
</StackPanel>

If you can't see the file path in the TextBlock, then you probably haven't set your DataContext to the instance of your view model. If you can see the text, then the problem is with your file path.


UPDATE 3 >>>

In .NET 4, the above Image.Source values would work. However, Microsoft made some horrible changes in .NET 4.5 that broke many different things and so in .NET 4.5, you'd need to use the full pack path like this:

<Image Source="pack://application:,,,/AssemblyName;component/Images/image_to_use.png">

For further information on pack URIs, please see the Pack URIs in WPF page on Microsoft Docs.

Sheridan
  • 68,826
  • 24
  • 143
  • 183
  • Thanks for the response. I tried that code, put a breakpoint in the DisplayedImage and it is definitely being accessed but no image. – kurgaan Feb 14 '14 at 20:46
  • Sorry, meaning that no image appears on the form. If I put the path directly in the XAML, the image shows. – kurgaan Feb 14 '14 at 20:53
  • Yeah, sorry, I didn't see your property properly... It's even easier than that. See my edit. – Sheridan Feb 14 '14 at 20:54
  • Well, this is getting me nowhere. Does anyone have tested code with a bound wpf image? – kurgaan Feb 14 '14 at 21:50
  • I'm terribly sorry for not getting this earlier. Thank you Sheridan. I have two tabs on a tab control that use the same UserControl on each but the difference is the binding. Your last update made me realize that I was looking at the wrong tab because the binding wasn't set up. Thank you for the help. You are awesome. – kurgaan Feb 14 '14 at 22:24
  • It works when the path is "C:\folder\...\image.jpg" but I have not been able to get it to work with "/AppName;component/Images/ImageName.jpg". Is there a trick to this? – kurgaan Feb 17 '14 at 15:51
  • Yes... change `AppName` to the name of *your* WPF Application and `ImageName.jpg` to the name of *your* image. Also make sure that you have a folder named `Images` in the root of your project folder. – Sheridan Feb 17 '14 at 16:33
  • Adding the path will not work for dynamically generated images... unfortunately that is my problem right now. I have a in-memory BitmapImage bound to the view, but it simply does not update when I change it. It only binds the first time the view is shown... – Loudenvier Dec 06 '14 at 03:09
  • I don't really understand this. If i put a string literal in xaml, the "pack://application:,,,/AssemblyName;component/Images/image_to_use.png" with the correct name and file... Boom, done. But when i bind the string to the VM, no go. I even set a breakpoint on it and verified the string is exactly the same. Hmmm... – Michael Schmidt May 11 '15 at 02:30
  • It sounds like you have a `Binding` error @MichaelSchmidt... look in your Visual Studio Output window for details. If that doesn't help, please ask a new question. – Sheridan May 11 '15 at 08:07
  • Having used this method I did come across one issue in that the resource's handle becomes locked by the app and the resource then cannot be changed. I had to add a converter for the binding so that a cached bitmap image gets loaded from the uri. – MultiColourPixel Dec 30 '15 at 13:14
  • I can't reproduce the issue with .NET 4.5+, the shorter version still works fine for me. – Ray Oct 27 '17 at 13:58
  • But I have the image as a property already loaded. Source only works with file paths – John Demetriou Mar 27 '18 at 11:35
  • How to bind image from url? – GlacialMan Sep 06 '18 at 11:21
  • @GlacialMan, see (How to bind to an Image using a dynamic URL in WPF?)[https://stackoverflow.com/questions/580975/how-to-bind-to-an-image-using-a-dynamic-url-in-wpf]. – Sheridan Sep 12 '18 at 16:04
  • @Sheridan, thank you very much, in VS2022 your suggestion works very well – Stefan Wuebbe Feb 07 '22 at 23:42
8

If you have a process that already generates and returns an Image type, you can alter the bind and not have to modify any additional image creation code.

Refer to the ".Source" of the image in the binding statement.

XAML

<Image Name="imgOpenClose" Source="{Binding ImageOpenClose.Source}"/>

View Model Field

private Image _imageOpenClose;
public Image ImageOpenClose
{
    get
    {
        return _imageOpenClose;
    }
    set
    {
        _imageOpenClose = value;
        OnPropertyChanged();
    }
}
Galactic
  • 400
  • 4
  • 14
6

@Sheridan thx.. if I try your example with "DisplayedImagePath" on both sides, it works with absolute path as you show.

As for the relative paths, this is how I always connect relative paths, I first include the subdirectory (!) and the image file in my project.. then I use ~ character to denote the bin-path..

    public string DisplayedImagePath
    {
        get { return @"~\..\images\osc.png"; }
    }

This was tested, see below my Solution Explorer in VS2015..

example of image binding in VS2015)

Note: if you want a Click event, use the Button tag around the image,

<Button Click="image_Click" Width="128" Height="128"  Grid.Row="2" VerticalAlignment="Top" HorizontalAlignment="Left">
  <Image x:Name="image" Source="{Binding DisplayedImagePath}" Margin="0,0,0,0" />
</Button>
Community
  • 1
  • 1
Goodies
  • 1,951
  • 21
  • 26