WPF 值转换器中的异步加载图像
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/24731335/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Async loading images in WPF value converter
提问by scott
I have a WPF listbox, which will bind a lot of images. Each image may will from local disk or get icon from Exe itself.
我有一个 WPF 列表框,它将绑定很多图像。每个图像可能来自本地磁盘或从 Exe 本身获取图标。
I put all those parse codes in MultiValueConverter. But it now seems block the UI. How to make that async?
我将所有这些解析代码放在 MultiValueConverter 中。但现在似乎阻止了用户界面。如何使异步?
Code Sample: https://github.com/qianlifeng/Wox/blob/master/Wox/Converters/ImagePathConverter.cs#L53
代码示例:https: //github.com/qianlifeng/Wox/blob/master/Wox/Converters/ImagePathConverter.cs#L53
回答by pushpraj
You can leverage IsAsyncproperty of Binding
您可以利用IsAsync的财产Binding
From MSDN:
从MSDN:
Use the IsAsync property when the get accessor of your binding source property might take a long time. One example is an image property with a get accessor that downloads from the Web. Setting IsAsync to true avoids blocking the UI while the download occurs.
当绑定源属性的 get 访问器可能需要很长时间时,请使用 IsAsync 属性。一个示例是带有从 Web 下载的 get 访问器的图像属性。将 IsAsync 设置为 true 可避免在下载发生时阻塞 UI。
example
例子
<Image Source="{Binding MyImage,IsAsync=True, Converter={StaticResource MyConverter}}" />
more on Binding.IsAsync
更多关于Binding.IsAsync
Async Converter
异步转换器
I managed to create a async converter
我设法创建了一个异步转换器
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; }
}
}
}
this converter will return an instance of AsyncTaskwhich will encapsulate the long running job within
此转换器将返回一个实例,AsyncTask该实例将在其中封装长时间运行的作业
class AsyncTaskwill execute the task asynchronously and will set the result to AsyncValueas it also implements INotifyPropertyChangedhence using the notification to update the UI
类AsyncTask将异步执行任务并将结果设置 AsyncValue为它也实现INotifyPropertyChanged因此使用通知来更新 UI
usage
用法
<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>
Idea is to bind the DataContextof the element to the converter and the desired property to the AsyncValue of the new data context
想法是将DataContext元素的绑定到转换器,将所需的属性绑定到新数据上下文的 AsyncValue
above example is using Text property of a text block for easy demo
上面的例子是使用文本块的 Text 属性来简单演示
exmaple is made for a IValueConvertersame approach can be used for IMultiValueConvertertoo.
exmaple 是为IValueConverter同样的方法制作的,也可以用于IMultiValueConverter。
回答by Harsh Baid
First you should provide some sample code so it easy to reproduce for answerers.
首先,您应该提供一些示例代码,以便回答者轻松重现。
IsAsyncwill not help
IsAsync不会有帮助
Using IsAsyncbinding will not help because of below reasons:
IsAsync由于以下原因,使用绑定将无济于事:
- I have observed that when loading images dynamically with IsAsync it will lead to memory leaks at times. So avoid this sugar candy
IsAsyncproperty IsAsyncwill not always help as one problem case mentioned in the question herewhere OP is trying to load image from web but wpf is resolving DNS on main thread so again application hangs for while
- 我观察到,当使用 IsAsync 动态加载图像时,它有时会导致内存泄漏。所以避免这种糖果
IsAsync属性 IsAsync作为这里问题中提到的一个问题案例,并不总是有帮助,其中 OP 试图从 Web 加载图像,但 wpf 正在主线程上解析 DNS,因此应用程序再次挂起一段时间
Solution is Use Attached Binding Property in WPF
解决方案是在 WPF 中使用附加绑定属性
Details:
细节:
- You should put some thumbnail image on
Sourcein XAML - Write one Attached Property class to load the image in background and Update Image Source in when its available (sample code below for similar kind of use case)
- 你应该
Source在 XAML 中放一些缩略图 - 编写一个附加属性类以在后台加载图像并在可用时更新图像源(以下示例代码用于类似的用例)
<Image my:ImageAsyncHelper.SourceUri="{Binding Author.IconUrl}" />
Attached Property class
附加属性类
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;
}
}
}
}
And if you need to use IMultiValueConverterwith attached property defined above then it should go like below xaml code:
如果你需要使用IMultiValueConverter上面定义的附加属性,那么它应该像下面的 xaml 代码:
Attached Property with IMultiValueConverter
附加属性 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>
Reference links
参考链接

