0

I have this xaml:

<Window x:Class="TestWPF.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" SizeToContent="WidthAndHeight">
        <Image Width="100" Height="100" Source="{Binding theImage}"/>
</Window>

And this code behind:

namespace TestWPF
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window, INotifyPropertyChanged
    {
        BitmapImage theImage = new BitmapImage();
        public MainWindow()
        {
            InitializeComponent();
            theImage.BeginInit();
            theImage.UriSource = new Uri("dice.png", UriKind.Relative);
            theImage.CacheOption = BitmapCacheOption.OnLoad;
            theImage.EndInit();
            OnPropertyChanged("theImage");
        }

        public event PropertyChangedEventHandler PropertyChanged;
        protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

Why is the image not showing up? I understand my code may be completely backwards. I'm just having trouble wrapping my head around the WPF way. Where things like this in Qt are dead simple, I can't seem to find anything relevant for this.

rubenvb
  • 74,642
  • 33
  • 187
  • 332

3 Answers3

1

BitmapImage theImage should be a property, binding can't be used with fields.

    public BitmapImage theImage {get; set;}

    public MainWindow()
    {
        InitializeComponent();

        DataContext = this;

        theImage = new BitmapImage();
        theImage.BeginInit();
        theImage.UriSource = new Uri("dice.png", UriKind.Relative);
        theImage.CacheOption = BitmapCacheOption.OnLoad;
        theImage.EndInit();
        OnPropertyChanged("theImage");
    }
Anton Danylov
  • 1,491
  • 10
  • 16
1

Give your Image a name

<Image x:Name="MyImage" Width="100" Height="100"/>

and assign the BitmapImage to the source property in the ctor of your mainwindow

public MainWindow()
    {
        InitializeComponent();
        theImage.BeginInit();
        theImage.UriSource = new Uri("dice.png", UriKind.Relative);
        theImage.CacheOption = BitmapCacheOption.OnLoad;
        theImage.EndInit();
        MyImage.Source = theImage;
    }
Jehof
  • 34,674
  • 10
  • 123
  • 155
  • This works, as does setting the `DataContext` explicitly to (in this case) `this`, as in @Anton's answer. – rubenvb Mar 18 '16 at 12:19
0

The recommended pattern for WPF applications is MVVM, where you have a view model class that declares the source properties of the bindings in the view (and implements the INotifyPropertyChanged interface to notify about property value changes):

public class ViewModel : INotifyPropertyChanged
{
    private ImageSource theImage;

    public ImageSource TheImage
    {
        get { return theImage; }
        set
        {
            theImage = value;
            OnPropertyChanged();
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

In your view you would assign the DataContext property to an instance of the view model. If you don't set the DataContext, the source objects of the bindings would have to be set explicitly.

public MainWindow()
{
    InitializeComponent();

    var vm = new ViewModel();
    DataContext = vm;

    vm.TheImage = new BitmapImage(new Uri("dice.png", UriKind.Relative));
}

The binding in your XAML would look like this:

<Image ... Source="{Binding TheImage}"/>
Clemens
  • 123,504
  • 12
  • 155
  • 268
  • Right, and for simplicity's sake, the `MainWindow` class is also my `ViewModel`. Nothing prevents that from working. – rubenvb Mar 18 '16 at 12:15
  • Of course not, but separating view and view model makes things easier to understand. Anyway, your approach would require `DataContext = this;` in the MainWindow constructor, and `theImage` being a public property instead of a field. – Clemens Mar 18 '16 at 12:18
  • Right. So that, and not an explanation of MVVM, is the answer to my question. Question then becomes why `DataContext` is not set to a sane default in the first place. – rubenvb Mar 18 '16 at 12:22
  • Because `this`is not a "sane default" in many cases, e.g. UserControls. – Clemens Mar 18 '16 at 12:22