3

I am trying to build a custom control, based on Image, which simply makes the image reload (from the same URI) on a timer. The original image is displaying fine, but it doesn't seem to refresh.

And here is custom control:

public class RefreshImage : Image
{
    protected override void OnInitialized(EventArgs e)
    {
        base.OnInitialized(e);
        this.Loaded += RefreshImage_Loaded;
    }

    private void RefreshImage_Loaded(object sender, RoutedEventArgs e)
    {
        var timer = new DispatcherTimer();
        timer.Interval = TimeSpan.FromSeconds(1);
        timer.Tick += RefreshImage_Tick;
        timer.Start();
    }

    private void RefreshImage_Tick(object sender, System.EventArgs e)
    {
        var bm = (BitmapImage) Source;
        bm.InvalidateProperty(BitmapImage.UriSourceProperty);
    }
 }

And I'm using it like so:

  <custom:RefreshImage>
      <Image.Source>
          <BitmapImage UriCachePolicy="NoCacheNoStore"
                       CreateOptions="IgnoreImageCache" CacheOption="None"
                       UriSource="{Binding Uri}"/>
      </Image.Source>
  </custom:RefreshImage>

Documentation for InvalidateProperty seems to indicate it's exactly what I need:

You can also use InvalidateProperty to force re-evaluation of a binding against a data source that is not able to implement the recommended INotifyPropertyChanged notification mechanism.

Raising an INotifiyPropertyChanged.PropertyChanged event on the Uri also does not trigger the image to reload.

Clemens
  • 123,504
  • 12
  • 155
  • 268
Jack Ukleja
  • 13,061
  • 11
  • 72
  • 113
  • Can you change (write to) the Image when it is opened in your application? – rmojab63 Feb 14 '17 at 04:19
  • Out of curiosity I tried to see if this just works with a simple databinding on UriSource...it doesn't. See thread here from 2006: https://social.msdn.microsoft.com/Forums/vstudio/en-US/85cffb5c-05a4-4653-a263-183f20ddd2c2/xaml-setting-bitmapimageurisource-from-binding-doesnt-work?forum=wpf Seems that UriSource is a set once dependency property. Subsequent changes seem to do nothing – Jack Ukleja Feb 14 '17 at 04:56
  • This question is not a duplicate. This question is about why UriSource cannot be changed once set. – Jack Ukleja Feb 14 '17 at 23:26

1 Answers1

0

Seems that BitmapSource are, in general, immutable objects. Once they have finished being initialized any further property changes are ignored. I suspect this includes the UriSource.

This following phase is repeated often in this MSDN post on creating custom ImageSources:

The ISupportInitialize interface is used to snap the values of the properties when initialization is complete. Further changes to the properties are ignored.

Glorfindel
  • 21,988
  • 13
  • 81
  • 109
Jack Ukleja
  • 13,061
  • 11
  • 72
  • 113
  • 1
    "Once the properties are set they are frozen" is not true. A BitmapImage isn't frozen unless you actually call Freeze(). In fact, WPF caches images that are loaded from URIs. If you would change the value of the Uri view model property, the Binding would update the BitmapImage's UriSource. – Clemens Feb 14 '17 at 07:15
  • @Clemens "If you would change the value of the Uri view model property, the Binding would update the BitmapImage's UriSource" <- Nope it doesn't work. Try it yourself. – Jack Ukleja Feb 14 '17 at 23:22
  • I did. Of course the Uri value must be different, and the property must fire a PropertyChanged event. Be aware that a changed value of the binding source property (Uri) does not mean that the target dependency property (UriSource) is set to a new *local value*. It is initially once set to a Binding, and that doesn't change later. Instead the value produced by the Binding changes. – Clemens Feb 15 '17 at 06:49
  • I have tried setting bound Uri to something different. As I said it doesn't work. I am not sure what you are doing differently to me. The binding may produce a different value, but its ignored by BitmapImage or causes it to throw an exception. Here is a sample project demonstrating it not working: https://expirebox.com/download/9da54d9e5e1f8004ba65ba26e0a5b77b.html – Jack Ukleja Feb 15 '17 at 07:19
  • Not sure what I've tested there. Pretty sure exactly what you did in that sample project. I'll check it later. – Clemens Feb 15 '17 at 08:59
  • You certainly know that already, but you may just bind the RefreshImage's `Source` property to the `Uri` instead of setting a BitmapImage in XAML with a bound `UriSource` property. – Clemens Feb 15 '17 at 09:06