无效的跨线程访问问题 [英] Invalid cross-thread access issue

查看:144
本文介绍了无效的跨线程访问问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有两个视图模型类:PersonViewModel和PersonSearchListViewModel。其中一个字段PersonViewModel农具是通过WCF下载的轮廓图像(独立存储本地缓存)。该PersonSearchListViewModel是一个容器类,用于保存人的名单。由于加载图像是比较重的,PersonSearchListViewModel只加载图像当前,下一个和previous页面(结果分页上UI)......以进一步提高我把另一个线程的图像载入图像的负荷。但是多线程的方法会导致跨线程访问问题。

I have two ViewModel classes : PersonViewModel and PersonSearchListViewModel. One of the fields PersonViewModel implements is a profile image that is downloaded via WCF(cached locally in isolated storage). The PersonSearchListViewModel is a container class that holds a list of Persons. Since loading images is relatively heavy, PersonSearchListViewModel loads only images for the current, next and previous page (results are paged on UI)...to further improve the load of images I put the load of images on another thread. However multi-threading approach causes cross-thread access issues.

PersonViewModel:

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:

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();
        }
    }
}

你如何处理多线程的方式ViewModel类的数据?我知道,你必须使用调度员对UI进行更新。如何更新绑定到UI视图模型?

How do you process data in ViewModel class in multi-threaded manner ? I know you have to use dispatcher on UI to update. How do you update ViewModel that is bound to UI ?

**编辑**

有也多了一个奇怪的错误发生。在下面的code:

There is also one more weird error happening. In the code below :

        public void GetBitmap(int imageID, Action<BitmapImage> callback)
        {
            // Get from server 
            bitmapCallback = callback;

            memorialFileServiceClient.GetImageCompleted += new EventHandler<GetImageCompletedEventArgs>(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对象吗?

I get a cross-thread error when trying to create a new BitmapImage object in background thread. Why can't I create a new BitmapImage object on a background thread ?

推荐答案

为了以更新视图模型一个的DependencyProperty,使用相同的调度员,你会用它来访问任何其他的UIElement:

In order to update a DependencyProperty in a ViewModel, use the same dispatcher you would use to access any other UIElement:

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

此外,BitmapImages有UI线程上被实例化。这是因为它使用DependencyProperties,这只能在UI线程上被使用。我曾尝试在单独的线程实例BitmapImages,它只是不工作。您可以尝试使用一些其他手段来存储在内存中的图像。例如,当你下载的图像,将其存储在一个MemoryStream。那么UI线程上的BitmapImage可以设置它的源到的MemoryStream。

Also, BitmapImages have to be instantiated on the UI thread. This is because it uses DependencyProperties, which can only be used on the UI thread. I have tried instantiating BitmapImages on separate threads and it just doesn't work. You could try to use some other means to store images in memory. For example, when you download the image, store it in a MemoryStream. Then a BitmapImage on the UI thread can set its source to the MemoryStream.

您可以尝试在UI线程中实例化BitmapImages,然后做一切与另一个线程的BitmapImage ...但是,这会得到毛茸茸的,我甚至不能确定它会工作。下面就是一个例子:

You may try instantiating the BitmapImages on the UI thread and then do everything else with the BitmapImage on another thread... but that would get hairy and I'm not even sure it would work. The following would be an example:

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);

这篇关于无效的跨线程访问问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆