我有一个WPF列表框,它将绑定大量的图像。每个图像可能会从本地磁盘或从exe本身获取图标。异步加载图像在WPF值转换器
我把所有这些解析代码放在MultiValueConverter中。但它现在似乎阻止用户界面。如何使这种异步?
代码示例:https://github.com/qianlifeng/Wox/blob/master/Wox/Converters/ImagePathConverter.cs#L53
我有一个WPF列表框,它将绑定大量的图像。每个图像可能会从本地磁盘或从exe本身获取图标。异步加载图像在WPF值转换器
我把所有这些解析代码放在MultiValueConverter中。但它现在似乎阻止用户界面。如何使这种异步?
代码示例:https://github.com/qianlifeng/Wox/blob/master/Wox/Converters/ImagePathConverter.cs#L53
您可以利用的Binding
IsAsync
财产MSDN:
使用isAsync属性,当你绑定源的get访问 属性可能需要很长的时间。一个例子是一个图像属性,其中一个获取访问器的网页可从 下载。将IsAsync设置为true 可避免在发生下载时阻止UI。
例如
<Image Source="{Binding MyImage,IsAsync=True, Converter={StaticResource MyConverter}}" />
异步转换
我成功地创建一个异步转换器
namespace CSharpWPF
{
class AsyncConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return new AsyncTask(() =>
{
Thread.Sleep(4000); //long running job eg. download image.
return "success";
});
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
public class AsyncTask : INotifyPropertyChanged
{
public AsyncTask(Func<object> valueFunc)
{
AsyncValue = "loading async value"; //temp value for demo
LoadValue(valueFunc);
}
private async Task LoadValue(Func<object> valueFunc)
{
AsyncValue = await Task<object>.Run(()=>
{
return valueFunc();
});
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs("AsyncValue"));
}
public event PropertyChangedEventHandler PropertyChanged;
public object AsyncValue { get; set; }
}
}
}
该转换器将返回AsyncTask
实例,它将封装长时间运行的作业中AsyncTask
类将异步执行任务,并将结果设置为AsyncValue
,因为它也因此使用通知更新实现INotifyPropertyChanged
UI
用法
<Grid xmlns:l="clr-namespace:CSharpWPF">
<Grid.Resources>
<l:AsyncConverter x:Key="AsyncConverter" />
</Grid.Resources>
<TextBlock DataContext="{Binding MyProperty,Converter={StaticResource AsyncConverter}}"
Text="{Binding AsyncValue}" />
</Grid>
思想是将元件的DataContext
结合到所述转换器和叔他所希望的属性,以
例如以上是使用文本块的文本属性,便于演示
〔实施例为IValueConverter
相同的方法可以用于IMultiValueConverter
太所作的新数据上下文的AsyncValue。
首先,您应该提供一些示例代码,以便为答复者重现。
IsAsync
不会帮助
使用IsAsync
结合的,因为以下原因,将不利于:
IsAsync
财产IsAsync
不会总是帮助作为question here提到的一个问题情况下OP正试图从网络加载图像,但WPF是如此再解决在主线程上的DNS应用程序挂起而的解决方案是使用连接绑定属性在WPF
详情:
Source
Ë缩略图图像<Image my:ImageAsyncHelper.SourceUri="{Binding Author.IconUrl}" />
附加属性类
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;
}
}
}
}
如果你需要使用IMultiValueConverter
与上述定义的附加属性,那么它应该像下面XAML代码:
附加属性与IMultiValueConverter
<Image>
<my:ImageAsyncHelper.SourceUri>
<MultiBinding Converter="{StaticResource MyImageMultiValueConverter}">
<Binding Source="Author" Path="IconUrl"/> <!-- Binding Parameters -->
<Binding Path="ImageType"/> <!-- Binding Parameters -->
<Binding Path="MyParameterToConverter"/> <!-- Binding Parameters -->
</MultiBinding>
</my:ImageAsyncHelper.SourceUri>
</Image>
参考链接
尽管警告不要使用它,但此解决方案似乎完全依赖于'IsAsync'(在新的Binding()'代码中)。 –
您应该在此处发布代码的相关部分。 – Clemens