异步创建和更新UI元素
本文关键字:UI 元素 更新 创建 异步 | 更新日期: 2023-09-27 18:04:38
我正在尝试将几个图像异步加载到ui中。
当一个图像被加载时(一个位图是通过路径创建的),该图像应该被设置为窗口上矩形的填充。
当我把bitmapimage的创建也放在Dispatcher中时。调用方法,代码工作。但很明显,我希望繁重的工作(创建位图)在线程中完成,而不是在调用中完成。
我已经尝试了几种解决方案,包括后台工作人员,但我不能让它工作。现在我有以下代码:
private void Window_ContentRendered(object sender, EventArgs e)
{
Thread loadThread = new Thread(new ThreadStart(LoadImagesAsync));
loadThread.Start();
}
private void LoadImagesAsync()
{
IEnumerable<string> images = System.IO.Directory.GetFiles(IMAGE_FOLDER, "*.jpg").Skip(_PageNumber * NUMBER_OF_IMAGES).Take(NUMBER_OF_IMAGES);
for (int i = 0; i < NUMBER_OF_IMAGES; i++)
{
var bitm = new BitmapImage(new Uri(images.ElementAt(i)));
this.Dispatcher.Invoke(() =>
{
Grid grid = (Grid)grd_photoBox.Children[i];
var rectangle = (from e in grid.Children.OfType<Rectangle>()
where e is Rectangle
select e).First();
ImageBrush brush = new ImageBrush(bitm);
rectangle.Fill = brush;
});
}
}
我得到以下异常:
The calling thread cannot access this object because a different thread owns it.
什么线索吗?
对于大图像,使用下面的代码,它将直接重新缩放图像并在其他线程中加载,然后在主线程中加载,以确保图像立即加载。编辑以下值以更改加载格式:
bitm.DecodePixelWidth = 200;
bitm.DecodePixelHeight = 100;
private void LoadImagesAsync()
{
IEnumerable<string> images = System.IO.Directory.GetFiles(IMAGE_FOLDER, "*.jpg").Skip(_PageNumber * NUMBER_OF_IMAGES).Take(NUMBER_OF_IMAGES);
for (int i = 0; i < NUMBER_OF_IMAGES; i++)
{
int j = i;
var bitm = new BitmapImage();
bitm.BeginInit();
bitm.CacheOption = BitmapCacheOption.OnLoad;
bitm.UriSource = new Uri(images.ElementAt(i));
bitm.DecodePixelWidth = 200;
bitm.DecodePixelHeight = 100;
bitm.EndInit();
ImageBrush brush = new ImageBrush(bitm);
brush.Freeze();
this.Dispatcher.BeginInvoke(new Action(() =>
{
Grid grid = (Grid)grd_photoBox.Children[j];
var rectangle = (from e in grid.Children.OfType<Rectangle>()
where e is Rectangle
select e).First();
rectangle.Fill = brush;
}));
}
}
诀窍是冻结位图以允许其他线程访问。因此,您还必须确保位图在创建时立即加载,因为默认行为是惰性加载。
var bitm = new BitmapImage();
bitm.BeginInit();
bitm.CacheOption = BitmapCacheOption.OnLoad; // load immediately
bitm.UriSource = new Uri(images.ElementAt(i));
bitm.EndInit();
bitm.Freeze();
我尝试了下面的代码,它为我工作。
Task<IEnumerable<string>>.Factory.StartNew(() => System.IO.Directory.GetFiles(
imagePath,
"*.jpg")).
ContinueWith(task =>
{
foreach (var item in task.Result)
{
this.Dispatcher.BeginInvoke((Action)(() =>
{
var img = new Image
{
Source =
new BitmapImage(
new Uri(item))
};
LayoutRoot.Children.Add(img);
}));
}
});
LayoutRoot是我在xaml中的网格。