无效的跨线程访问问题

我有两个ViewModel类:PersonViewModel和PersonSearchListViewModel。 PersonViewModel实现的一个字段是通过WCF下载的配置文件映像(在独立存储中本地缓存)。 PersonSearchListViewModel是一个容器类,它包含一个Persons列表。 由于加载图像相对较重,因此PersonSearchListViewModel仅加载当前页面,下一页面和上一页面的图像(结果在UI上分页)…为了进一步改善图像的负载,我将图像的加载放在另一个线程上。 但是,multithreading方法会导致跨线程访问问题。

PersonViewModel:

public void RetrieveProfileImage() { Image profileImage = MemorialDataModel.GetImagePerPerson(Person); if (profileImage != null) { MemorialDataModel.ImageManager imgManager = new MemorialDataModel.ImageManager(); imgManager.GetBitmap(profileImage, LoadProfileBitmap); } } private void LoadProfileBitmap(BitmapImage bi) { ProfileImage = bi; // update IsProfileImageLoaded = true; } private BitmapImage profileImage; public BitmapImage ProfileImage { get { return profileImage; } set { profileImage = value; RaisePropertyChanged(new System.ComponentModel.PropertyChangedEventArgs("ProfileImage")); } } 

PersonSearchListViewModel:

 private void LoadImages() { // load new images Thread loadImagesThread = new Thread(new ThreadStart(LoadImagesProcess)); loadImagesThread.Start(); //LoadImagesProcess(); If executed on the same thread everything works fine } private void LoadImagesProcess() { int skipRecords = (PageIndex * PageSize); int returnRecords; if (skipRecords != 0) { returnRecords = 3 * PageSize; // page before, cur page and next page } else { returnRecords = 2 * PageSize; // cur page and next page } var persons = this.persons.Skip(skipRecords).Take(returnRecords); // load images foreach (PersonViewModel pvm in persons) { if (!pvm.IsProfileImageLoaded) { pvm.RetrieveProfileImage(); } } } 

如何以multithreading方式处理ViewModel类中的数据? 我知道您必须在UI上使用调度程序进行更新。 如何更新绑定到UI的ViewModel?

**编辑**

还有一个奇怪的错误发生了。 在下面的代码中:

  public void GetBitmap(int imageID, Action callback) { // Get from server bitmapCallback = callback; memorialFileServiceClient.GetImageCompleted += new EventHandler(OnGetBitmapHandler); memorialFileServiceClient.GetImageAsync(imageID); } public void OnGetBitmapHandler(object sender, GetImageCompletedEventArgs imageArgs) { if (!imageArgs.Cancelled) { // I get cross-thread error right here System.Windows.Media.Imaging.BitmapImage bi = new BitmapImage(); ConvertToBitmapFromBuffer(bi, imageArgs.Result.Image); // call call back bitmapCallback.Invoke(bi); } } 

尝试在后台线程中创建新的BitmapImage对象时出现跨线程错误。 为什么我不能在后台线程上创建新的BitmapImage对象?

要更新ViewModel中的DependencyProperty,请使用您用于访问任何其他UIElement的相同调度程序:

 System.Windows.Deployment.Current.Dispatcher.BeginInvoke(() => {...}); 

此外,必须在UI线程上实例化BitmapImages。 这是因为它使用DependencyProperties,它只能在UI线程上使用。 我尝试在不同的线程上实例化BitmapImages,它只是不起作用。 您可以尝试使用其他方法将图像存储在内存中。 例如,下载图像时,将其存储在MemoryStream中。 然后,UI线程上的BitmapImage可以将其源设置为MemoryStream。

您可以尝试在UI线程上实例化BitmapImages,然后在另一个线程上使用BitmapImage执行其他所有操作……但这样会变得毛茸茸,我甚至不确定它是否会起作用。 以下是一个例子:

 System.Windows.Media.Imaging.BitmapImage bi = null; using(AutoResetEvent are = new AutoResetEvent(false)) { System.Windows.Deployment.Current.Dispatcher.BeginInvoke(() => { bi = new BitmapImage(); are.Set(); }); are.WaitOne(); } ConvertToBitmapFromBuffer(bi, imageArgs.Result.Image); bitmapCallback.Invoke(bi); 

我相信你的UI线程存在交叉线程问题。

编辑绑定对象可能会强制更新工作线程上的UI,但无法成功。 每当更新绑定类时,您可能需要执行InvokeRequired / Invoke hokey-pokey。

你说你已经知道了,但供参考:

MSDN对线程安全的UI调用

可以使用WriteableBitmap实现。

  public void LoadThumbAsync(Stream src, WriteableBitmap bmp, object argument) { ThreadPool.QueueUserWorkItem(callback => { bmp.LoadJpeg(src); src.Dispose(); if (ImageLoaded != null) { Deployment.Current.Dispatcher.BeginInvoke(() => { ImageLoaded(bmp, argument); }); } }); } 

但是你必须在UI Thread中构造WriteableBitmap,然后加载可以在其他线程中执行。

  void DeferImageLoading( Stream imgStream ) { // we have to give size var bmp = new WriteableBitmap(80, 80); imageThread.LoadThumbAsync(imgStream, bmp, this); } 

在这篇博客文章中查看更多解释