How can I save a WPF image from locking if ImageSource refers to an unreachable url?

I am writing a WPF application and trying to associate an image with my view model with the following XAML:

<Image Source="{Binding Author.IconUrl, IsAsync=True}" /> 

The problem is that image URLs are user-defined and can often link to images hosted on intranet web servers. When a WPF application is launched remotely, it locks in an attempt to resolve images that are no longer available.

I thought the IsAsync binding property would cause the download to happen in the background, but it looks like DNS resolution can still happen in the main thread?

What can I do to keep my application locked even if images are not available?

Thanks Corey

+7
image dns wpf
source share
2 answers

Here is a new answer for you, hopefully better than the previous one.

When you create a binding with "IsAsync" true, it accesses the Author.IconUrl property in a separate thread, but does the conversion from Uri to ImageSource to the main thread. As you have discovered, the conversion performs a DNS lookup in the main thread, causing the application to block.

Since your source is http / https, WPF automatically handles the asynchronous loading of the image source. Therefore, I suspect that all you need to do is just an asynchronous DNS lookup.

This can be automated using the 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; } } } } 

How it works:

  • When you set the attached property, it creates an instance of ImageAsyncHelper and asynchronously associates Image.Source with the ImageSource prototype of the asynchronous helper object.
  • When the asynchronous binding is triggered, it calls the VerifiedUri authenticator, which checks the address available, then returns [
  • If the IconUri property ever changes, the binding updates the attached property, which creates and binds the new ImageAsyncHelper so that the images are kept up to date.
+10
source share

Well, I think I found out why this is happening ...

I searched Reflector a bit to try to figure out what exactly was caused. Inside BitmapDecoder, I found a simple call to WebRequest.BeginGetResponseStream.

I wrote a quick console application for testing:

 static void Main(string[] args) { DateTime start = DateTime.Now; WebRequest request = WebRequest.Create("http://nonexistserver/myicon.jpg"); IAsyncResult ar = request.BeginGetResponse((AsyncCallback)delegate(IAsyncResult result) { try { WebResponse response = request.EndGetResponse(result); } catch (Exception e) { Console.WriteLine(e); } }, null); Console.WriteLine(DateTime.Now - start); ar.AsyncWaitHandle.WaitOne(); Console.WriteLine("Done"); Console.ReadKey(); } 

Without starting Fiddler, the output is 2-3 seconds. With the launch of Fiddler, the output is ~ .25 seconds.

Performing another digging, it looks like a BeginGetResponse (which is used by WPF under the hood) until the name resolution is complete.

See this question: webrequest.begingetresponse takes too long when the url is invalid

So, I understand why the lock is happening now, but I do not know how to do this for my application .:(

0
source share

All Articles