我有一個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