Blocking UI happans because IsAsync=True runs in async manner only binding process. In your case you have a long running operation during converting process. To solve this you should create converter that presents the result asynchronously like this (based on this answer):
Create task complition notifier:
public sealed class TaskCompletionNotifier<TResult> : INotifyPropertyChanged
{
public TaskCompletionNotifier(Task<TResult> task)
{
Task = task;
if (task.IsCompleted) return;
task.ContinueWith(t =>
{
var temp = PropertyChanged;
if (temp != null)
{
temp(this, new PropertyChangedEventArgs("Result"));
}
});
}
// Gets the task being watched. This property never changes and is never <c>null</c>.
public Task<TResult> Task { get; private set; }
// Gets the result of the task. Returns the default value of TResult if the task has not completed successfully.
public TResult Result { get { return (Task.Status == TaskStatus.RanToCompletion) ? Task.Result : default(TResult); } }
public event PropertyChangedEventHandler PropertyChanged;
}
Create async converter implementing MarkupExtention:
public class ImageConverter: MarkupExtension, IValueConverter
{
public ImageConverter()
{
}
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value == null) return new BitmapImage();
var task = Task.Run(() =>
{
Thread.Sleep(5000); // Perform your long running operation and request here
return value.ToString();
});
return new TaskCompletionNotifier<string>(task);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
public override object ProvideValue(IServiceProvider serviceProvider)
{
return this;
}
}
Use it in Xaml:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<TextBox x:Name="uri" Grid.Row="0" Text="{Binding ImageUri, ElementName=main}"/>
<Image Grid.Row="1" DataContext="{Binding Text, ElementName=uri, Converter={local:ImageConverter}}" Source="{Binding Path=Result, IsAsync=True}"/>
</Grid>
Update 2 Seems like Image control load images asynchronously itself. You are right first load take a lot of time. You may use code like this:
try
{
var uri = Uri.Text;
var client = new WebClient();
var stream = await client.OpenReadTaskAsync(uri);
var source = new BitmapImage();
source.BeginInit();
source.StreamSource = stream;
source.EndInit();
Img.Source = source;
}
catch (Exception) { }
But its performance is't better than your variant.