c# - 无效的跨线程访问问题

标签 c# silverlight multithreading silverlight-3.0

我有两个 ViewModel 类:PersonViewModel 和 PersonSearchListViewModel。 PersonViewModel 实现的字段之一是通过 WCF 下载的配置文件图像(缓存在本地独立存储中)。 PersonSearchListViewModel 是一个包含人员列表的容器类。由于加载图片相对繁重,PersonSearchListViewModel 只加载当前、下一页和上一页的图片(结果在 UI 上分页)...为了进一步提高图片的加载,我将图片的加载放在另一个线程上。然而,多线程方法会导致跨线程访问问题。

人物 View 模型:

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

个人搜索 ListView 模型:

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 上使用调度程序来更新。如何更新绑定(bind)到 UI 的 ViewModel?

** 编辑 **

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

        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 对象?

最佳答案

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

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

此外,BitmapImages 必须在 UI 线程上实例化。这是因为它使用了只能在 UI 线程上使用的 DependencyProperties。我已经尝试在单独的线程上实例化 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);

关于c# - 无效的跨线程访问问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1924408/

相关文章:

Silverlight MVVM 绑定(bind)更新以不希望的顺序触发

c# - 美国邮政编码位于 2 个邮政编码中间?

c# - 如何为 <asp :button>? 的访问 key 添加下划线

c# - 如何在WP7 WebBrowser 控件中注入(inject)Javascript?

c - 在将控制权交给他们之前,如何列出所有子 pid?

java - 任务编排实现

C# Lazy <T> & 竞速初始化?

c# - StructureMap 开放通用类型

c# - 对 List<Socket> 的多次访问

c# - 使用具有多个后代的 Linq 解析 XML