我一直在尋找將影像系結/加載到串列的性能影響降至最低的方法。
我嘗試了人們在網上建議的幾種不同選項,例如:
https://social.msdn.microsoft.com/Forums/en-US/7fc238ea-194e-4f29-bcbd-9a3d4bdb2180/async-loading-of-bitmapsource-in-value-converter?forum=wpf
或使用單獨的執行緒將影像串列加載到 ImageSource 然后系結到串列視圖
和/或與標記為異步的主要源的優先級系結(當我單獨使用這種方法時,我沒有看到任何改進,tbh)
他們都有一定程度的改進,我最終得到了如下內容:一個帶有異步加載的自定義影像控制元件
public class AsyncImage : Image
{
private static ImageSource _blank;
private static Random random;
private static ImageSource Blank
{
get
{
if(_blank == null)
{
var bi = new BitmapImage();
bi.BeginInit();
Stream imgStream = File.OpenRead("D:\\...\\blankLoading.png");
bi.StreamSource = imgStream;
bi.EndInit();
bi.Freeze();
_blank = bi;
}
return _blank;
}
}
public string ImageUrl
{
get { return GetValue(ImageUrlProperty).ToString(); }
set
{
SetValue(ImageUrlProperty, value);
LoadImageAsync(value);
}
}
public static readonly DependencyProperty ImageUrlProperty =
DependencyProperty.Register("ImageUrl", typeof(string), typeof(AsyncImage), new UIPropertyMetadata(string.Empty, new PropertyChangedCallback(OnImageUrlChanged)));
private static void OnImageUrlChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
AsyncImage control = (AsyncImage)d;
control.ImageUrl = e.NewValue.ToString();
}
private void LoadImageAsync(string url)
{
Image image = new Image();
base.Source = Blank;
ThreadPool.QueueUserWorkItem((r) =>
{
BitmapImage bi = null;
bi = new BitmapImage();
bi.BeginInit();
var bytes = File.ReadAllBytes(url); //i want to make sure data is loaded before assignment
bi.StreamSource = new MemoryStream(bytes);
bi.EndInit();
bi.Freeze(); //makes sure your image can be passed across threads
Console.Write(url);
image.Dispatcher.Invoke(DispatcherPriority.Normal,
(ThreadStart)delegate
{
base.Source = bi; //this is where it actually comes back to UI thread
});
});
}
}
使用這種方法,我可以將 URL 串列或檔案路徑串列系結到串列視圖,資料系結將執行得更流暢......但是,當顯示實際影像時,它總是會導致 UI 有點凍結(在最后一行)。當您有一個完整的最后影像串列時,凍結會更加明顯。
有沒有辦法解決這個問題?我想要的是當影像顯示時用戶界面仍然可以回應......
uj5u.com熱心網友回復:
您的代碼有一些問題。您不得呼叫LoadImageAsync()該ImageUrl屬性的 setter 。該方法必須改為在 中呼叫OnImageUrlChanged。
在 LoadImageAsync 中,您創建一個 Image 元素只是為了使用它的 Dispatcher,這完全沒有意義。使用自定義控制元件的 Dispatcher,例如this.Dispatcher. 也寫this.Source而不是base.Source.
您還必須關閉加載 BitmapImage 的流。bi.CacheOption = BitmapCacheOption.OnLoad通過using塊設定和處理 MemoryStream 。
也就是說,考慮使用更現代的實作,沒有ThreadPool.QueueUserWorkItem和Dispatcher.Invoke。
使用Task.Run來代替:
public class AsyncImage : Image
{
public static readonly DependencyProperty ImagePathProperty =
DependencyProperty.Register(
nameof(ImagePath), typeof(string), typeof(AsyncImage),
new PropertyMetadata(async (o, e) =>
await ((AsyncImage)o).LoadImageAsync((string)e.NewValue)));
public string ImagePath
{
get { return (string)GetValue(ImagePathProperty); }
set { SetValue(ImagePathProperty, value); }
}
private async Task LoadImageAsync(string imagePath)
{
Source = await Task.Run(() =>
{
using (var stream = File.OpenRead(imagePath))
{
var bi = new BitmapImage();
bi.BeginInit();
bi.CacheOption = BitmapCacheOption.OnLoad;
bi.StreamSource = stream;
bi.EndInit();
bi.Freeze();
return bi;
}
});
}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/391796.html
標籤:C# 小白 图片 数据绑定 .net-framework-4.8
下一篇:如何從左側而不是右側溢位影像
