从线程方法获取价值

时间:2014-02-04 18:33:25

标签: c# wpf multithreading

我正在尝试访问数据库,获取图像并将其返回,然后可以在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;

我现在不知道该怎么办。 任何建议将不胜感激!

4 个答案:

答案 0 :(得分:4)

仅在UI线程上调用

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。