Here is a new answer for you, hopefully better than my earlier one.
When you create your binding with 'IsAsync' true, it executes the property access to Author.IconUrl on a separate thread but does the conversion from Uri to ImageSource in the main thread. As you discovered, the conversion does a DNS lookup on the main thread causing the application to lock up.
Since your source is http/https, WPF will automatically handle asynchronously loading the image source. So I suspect all you need to do is to make just the DNS lookup asynchronous.
This can be automated by using an attached property:
<Image my:ImageAsyncHelper.SourceUri="{Binding Author.IconUrl}" />
where ImageAsyncHelper is defined as:
public class ImageAsyncHelper : DependencyObject
{
public static Uri GetSourceUri(DependencyObject obj) { return (Uri)obj.GetValue(SourceUriProperty); }
public static void SetSourceUri(DependencyObject obj, Uri value) { obj.SetValue(SourceUriProperty, value); }
public static readonly DependencyProperty SourceUriProperty = DependencyProperty.RegisterAttached("SourceUri", typeof(Uri), typeof(ImageAsyncHelper), new PropertyMetadata
{
PropertyChangedCallback = (obj, e) =>
{
((Image)obj).SetBinding(Image.SourceProperty,
new Binding("VerifiedUri")
{
Source = new ImageAsyncHelper { GivenUri = (Uri)e.NewValue },
IsAsync = true,
});
}
});
Uri GivenUri;
public Uri VerifiedUri
{
get
{
try
{
Dns.GetHostEntry(GivenUri.DnsSafeHost);
return GivenUri;
}
catch(Exception)
{
return null;
}
}
}
}
The way this works is:
- When you set the attached property it creates an instance of an ImageAsyncHelper and asynchronously binds the Image.Source to the ImageSource propety of the async helper object.
- When the asynchronous binding fires it calls the VerifiedUri getter which verifies the address is accessible then returns the GivenUri
- If your IconUri property ever changes, the binding causes the attached property to update which creates and binds a new ImageAsyncHelper so the images stays up to date.