0

I've struggling for a while with strange DataBinding problem that only appears to be happening in WinRT. My Phone Project uses the same code and works without problems.

The first version of the code below doesn't work on WinRT while the second version does. The confusing thing is that I was under the assumption that the call to the "Icon" getter will always come from the UI thread and thus the synchronization context used for the async "DownloadIcon" method will be the right one. But apparently it is not.

What's even more confusing is that I've verified that I'm on the same thread (Thread 3) when the getter is accessed and when the setter raises the PropertyChanged event - regardless of the code version. But only the second version has the disired effect of the Icon propery getting re-queried after the download is complete.

Binding:

<DataTemplate x:Key="AppBarAlbumItemTemplateGrid">
  <Grid HorizontalAlignment="Left" Width="80" Height="80">
    <Grid.RowDefinitions>
      <RowDefinition Height="*"></RowDefinition>
      <RowDefinition Height="20"></RowDefinition>
    </Grid.RowDefinitions>
    <Border Grid.RowSpan="2" Background="{StaticResource ListViewItemPlaceholderBackgroundThemeBrush}">
      <Image Source="{Binding Icon}" Stretch="UniformToFill" />
    </Border>
    <Grid Grid.Row="1" VerticalAlignment="Bottom" Background="{StaticResource GIFPlayerOverlayBrush}">
      <TextBlock Text="{Binding Title}" VerticalAlignment="Center" FontSize="10" Foreground="{StaticResource ListViewItemOverlayForegroundThemeBrush}" Margin="5,0"/>
    </Grid>
  </Grid>
</DataTemplate>

This does not work properly:

public class Album : AlbumBase
{
  WeakReference<ImageSource> icon;

  public ImageSource Icon
  {
    get
    {
      ImageSource result;
      if (icon != null && icon.TryGetTarget(out result))
        return result;

      DownloadIcon();
      return null;
    }

    private set
    {
        this.RaiseAndSetIfChanged(ref icon, new WeakReference<ImageSource>(value));
    }
  }

  async void DownloadIcon()
  {
      Icon = await imageHelper.LoadImageFromUrlAsync(IconUrl, AppSettings.ThumbnailsFolder);
  }
}

This one does but why is it even necessary to capture the context?

public class Album : AlbumBase
{
  public Album()
  {
    this.synchronizationContext = SynchronizationContext.Current;
  }

  private SynchronizationContext synchronizationContext;
  WeakReference<ImageSource> icon;

  public ImageSource Icon
  {
    get
    {
      ImageSource result;
      if (icon != null && icon.TryGetTarget(out result))
        return result;

      DownloadIcon();
      return null;
    }

    private set
    {
      this.synchronizationContext.Post((x) =>
      {
        this.RaiseAndSetIfChanged(ref icon, new WeakReference<ImageSource>(value));
      }, null);
    }
  }

  async void DownloadIcon()
  {
      Icon = await imageHelper.LoadImageFromUrlAsync(IconUrl, AppSettings.ThumbnailsFolder);
  }
}
Oliver Weichhold
  • 10,259
  • 5
  • 45
  • 87
  • The first version should work (though it's not the way I would do it). Have you double-checked your `INotifyPropertyChanged` implementation? (It should be set first, then raised). – Stephen Cleary Jul 29 '13 at 12:03
  • @StephenCleary Stephen, even though I'm using ReactiveUIs implementation which is quite mature, I wrote my own implementation to be sure which didn't fix anything (as expected). Out of curiosity. How would you do it? – Oliver Weichhold Jul 29 '13 at 12:08
  • I talk a bit about [`async` properties](http://blog.stephencleary.com/2013/01/async-oop-3-properties.html) on my blog. In this case, I'd use my [`NotifyTaskCompletion` type](https://nitoasyncex.codeplex.com/wikipage?title=NotifyTaskCompletion) which allows data binding for the error condition as well as success (`async void` error handling isn't pretty). – Stephen Cleary Jul 29 '13 at 12:29
  • Try turning on [data binding tracing](http://stackoverflow.com/a/343206/263693). Hopefully that works on WinRT... – Stephen Cleary Jul 29 '13 at 12:32
  • @StephenCleary PresentationTraceSources seems to be not supported in WinRT – Oliver Weichhold Jul 29 '13 at 12:46
  • On a side note, it's a good practice to suffix async method names with Async (or TaskAsync if non Task returning one already exists). – Paulo Morgado Jul 30 '13 at 07:02

0 Answers0