WPF Binding Image Source

2019-01-20 15:59发布

问题:

maybe stupid question, but I don't know anymore...

I have ViewModel class like this:

public class MainWindowsViewModel : INotifyPropertyChanged
{
    private ImageSource _img;
    public ImageSource StatusImage
    {
        get { return _img; }
        set
        {
            _img = value;
            NotifyPropertyChanged();
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    private void NotifyPropertyChanged([CallerMemberName]String propertyName = "")
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
}

Binding in XAML looks like this:

  <Window.DataContext>
    <VM:MainWindowsViewModel />
  </Window.DataContext>
    <Image x:Name="gui_image_status" HorizontalAlignment="Left" Height="26" Margin="144,10,0,0" VerticalAlignment="Top" Width="29" Source="{Binding Path=StatusImage}" />

And I set content of ImageSource like this:

MainWindowsViewModel _view = new MainWindowsViewModel();

        var yourImage = new BitmapImage(new Uri(String.Format("Sources/{0}.png", "red"), UriKind.Relative));
        _view.StatusImage = yourImage;

But it does not work. I think that problem is in that NotifyPropertyChanged, because I tried place brake point in the set and get. Get triggered few times at the start, after then set triggered as well with correct ImageSource, but after then get did not triggered anymore. Like no setting ever happened.

It's really simply binding that I have done many times similarly...I don't know why it doesn't work this time.

回答1:

You are creating two instances of your MainWindowsViewModel class, one in XAML by

<Window.DataContext>
    <VM:MainWindowsViewModel />
</Window.DataContext>

and one in code behind by

MainWindowsViewModel _view = new MainWindowsViewModel();

So your code behind sets the property on a different view model instance than the one the view is bound to.

Change your code behind to this:

var viewModel = (MainWindowsViewModel)DataContext;
viewModel.StatusImage = new BitmapImage(...);


回答2:

I didn't find any problems in your code, but you can try to check few things.

  1. Check that your Image added to the project and set build action of images to Content (copy if newer).
  2. Before updating ImageSource call Freeze method to prevent error: "Must create DependencySource on same Thread as the DependencyObject"

    var yourImage = new BitmapImage(new Uri(String.Format("Sources/{0}.png", "red"), UriKind.Relative));
    yourImage.Freeze();
    _view.StatusImage = yourImage;
    

Also, there is an easier way to bind image in WPF. You can use string as a source and set a resource path to the binded property:

public string StatusImage  
{
    get { return "/AssemblyName;component/Sources/red.png"; }
}