我正在尝试访问数据库,获取图像并将其返回,然后可以在Border对象中显示。 (所以我也将byte []数据转换为图像) 此过程需要足够的时间来注意UI已冻结。
以下是一些代码:
ImageBrush imgb = new ImageBrush();
imgb.ImageSource = GlobalDB.GetImage(album.name, 400); // Size is 400px, this is the time-consuming part.
AlbumArt.Background = imgb;
我尝试使用背景工作者,但这给了我一个例外,说我不能从不同的线程调用。我得到了那个例外,因为BackgroundWorker.RunWorkerCompleted显然是由另一个线程所拥有的(?)
添加到最后一位:Runworkercompleted这样做了:
AlbumArt.Background = imgb;
我现在不知道该怎么办。 任何建议将不胜感激!
答案 0 :(得分:4)
RunWorkerCompleted
。
我只能在您的代码中看到 imgb
是在后台线程中创建的,WPF的约束是 DependencyProperty源和Dependency对象应该在同一个线程。 强>
所以在将imgb分配给背景调用Freeze()
之前:
imgb.Freeze();
AlbumArt.Background = imgb;
原因是 freezed objects are allowed to be access across threads
。它们不是线程仿射。
答案 1 :(得分:1)
不确定GetImage正在做什么,但也许您可以将代码封装到任务中:
Task.Factory.StartNew(() => {
ImageBrush imgb = new ImageBrush();
imgb.ImageSource = GlobalDB.GetImage(album.name, 400);
AlbumArt.Background = imgb;
});
答案 2 :(得分:1)
正如在另一个答案中已经建议的那样,您也可以使用异步任务。但是,在冻结ImageBrush之后,您必须将Background
属性的赋值分配给UI线程。
Task.Factory.StartNew(() =>
{
var imgb = new ImageBrush(GlobalDB.GetImage(album.name, 400));
imgb.Freeze();
Dispatcher.BeginInvoke(new Action(() => AlbumArt.Background = imgb));
});
答案 3 :(得分:1)
我不得不问。您的视图模型在哪里? Rohit Vats的回答将或多或少地完成工作,但你并没有习惯性地接近这一点。你应该有一个ViewModel代码如下:
public class AlbumViewModel: BaseViewModel // BaseViewModel is your code that implements INotifyPropertyChanged
{
private string name
public string Name
{
get{ return name;}
set
{
if(name != value)
{
name = value;
FirePropertyChanged("Name");
LoadBackgroundImageAsync(value);
}
}
}
private ImageSource backgroundImage;
public ImageSource BackgroundImage
{
get{return backgroundImage;}
private set
{
if(backgroundImage != value)
{
background = value;
FirePropertyChanged("BackgroundImage");
}
}
}
private Task LoadBackgroundImageAsync(string name)
{
var retv = new Task(()=>
{
var source = GlobalDB.GetImage(name, 400);
source.Freeze();
BackgroundImage = source;
});
retv.Start();
return retv;
}
}
然后只需绑定到该属性,让WPF了解更新UI。