我的WPF MVVM应用程序通过Webclient.DownloadFileAsync(url, fileLocation)
从给定URL异步加载图像。该过程进行得很顺利,下载图片时完全不会冻结。但是,当我向用户展示图像文件时,就会出现问题-应用程序变得无响应。
下载文件后,我将图像文件分配给BitmapImage:
public async void LoadFileToBitmapImage(string filePath)
{
_isDownloading = false;
await FileToBitmapImage(filePath);
}
public Task FileToBitmapImage(string filePath)
{
return Task.Run(() =>
{
var executableLocation = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
var imageLocation = Path.Combine(executableLocation, filePath);
var bi = new BitmapImage();
bi.BeginInit();
bi.UriSource = new Uri(imageLocation);
bi.EndInit();
bi.Freeze();
Image = bi;
});
}
Image.cs:
private BitmapImage _image;
public BitmapImage Image
{
get => _image;
set
{
_image = value;
NotifyOfPropertyChange("Image");
}
}
XAML图像绑定:
<Image Source="{Binding Image, IsAsync=True}" Margin="3"/>
下载图像并将其呈现给用户时会出现问题。图像越大,向用户呈现图像的时间就越多,并且应用程序无响应的时间也就越多。
我当时尝试在应用程序冻结以检查线程并获取the following info时单击“暂停”,但不幸的是它没有向我提供任何信息。
任何帮助将不胜感激!
修改
值得一提的是,在引发PropertyChanged事件之后而不是在之后,应用程序变得无响应。也许与向UI渲染图像有关?
答案 0 :(得分:-1)
我花了几天时间找到解决此问题的简单方法。我需要在不冻结UI的情况下高质量显示一百多个图像。
我尝试了对绑定的各种修改,等等,最后,只有在Image出现在界面元素树中之前,通过代码和Source属性集的创建,才能创建Image控件。
在XAML中,只有空的ContentControl:
<ContentControl x:Name="ImageContent"/>
在代码中:
static readonly ConcurrentExclusiveSchedulerPair _pair = new ConcurrentExclusiveSchedulerPair();
// Works for very big images
public void LoadImage(Uri imageUri)
{
var image = new System.Windows.Controls.Image(); // On UI thread
RenderOptions.SetBitmapScalingMode(image, BitmapScalingMode.HighQuality);
Task.Factory.StartNew(() =>
{
var source = new BitmapImage(imageUri); // load ImageSource
Dispatcher.RunOnMainThread(() =>
{
image.Source = source; // Set source while not in UI
// Add image in UI tree
ImageContent.Content = image; // ImageContent is empty ContentControl
ImageContent.InvalidateVisual();
});
}, default, TaskCreationOptions.LongRunning, _pair.ExclusiveScheduler);
}
通过CacheOption OnLoad加载图像效果更好。
public static ImageSource BitmapFromUri(Uri source)
{
if (source == null)
return new BitmapImage(source);
using (var fs = new FileStream(source.LocalPath, FileMode.Open))
{
var bitmap = new BitmapImage();
bitmap.BeginInit();
bitmap.StreamSource = fs;
bitmap.CacheOption = BitmapCacheOption.OnLoad;
bitmap.EndInit();
bitmap.Freeze();
return bitmap;
}
}