我有一个WPF列表框,它会绑定很多图像。每个图像可能来自本地磁盘或从Exe本身获取图标。
我将所有这些解析代码放在MultiValueConverter中。但它现在似乎阻止了UI。如何使该异步?
代码示例:https://github.com/qianlifeng/Wox/blob/master/Wox/Converters/ImagePathConverter.cs#L53
答案 0 :(得分:7)
您可以利用IsAsync
Binding
属性
来自MSDN:
在绑定源的get访问器时使用IsAsync属性 财产可能需要很长时间。一个例子是带有的图像属性 从Web下载的get访问器。将IsAsync设置为true 避免在下载过程中阻止UI。
例如
<Image Source="{Binding MyImage,IsAsync=True, Converter={StaticResource MyConverter}}" />
更多关于Binding.IsAsync
异步转换器
我设法创建了一个异步转换器
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
的实例,该实例将封装长期运行的作业
class 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
绑定到转换器,将所需属性绑定到新数据上下文的AsyncValue
以上示例使用文本块的Text属性进行简单演示
例如,IValueConverter
同样的方法也适用于IMultiValueConverter
。
答案 1 :(得分:-1)
首先,您应该提供一些示例代码,以便为回答者轻松复制。
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>
参考链接