Update an ObservableCollection with a background worker in MVVM

jpg*_*ner 10 c# wpf multithreading observablecollection

Ok, I recently implemented a background worker to perform saving and loading of data.

However, getting this to work on a save command has proved difficult.

基本上,我的save命令生成一个事件,该事件通知集合视图模型,已添加Item,并且该项应添加到其自己的ObservableCollection中.

此时,我得到通常的异常,说我不能在不同的线程上更新ICollection.我已经尝试创建一个调用的新列表类型Dispatcher.Invoke,但是这仍然会生成相同的异常.

我想知道是否有其他人对如何最好地解决这个问题有任何建议?

所以目前我有一个继承自ObservableCollection的类:

public class ThreadSafeObservableCollection<T> : ObservableCollection<T>
{
    public ThreadSafeObservableCollection(List<T> collection)
        : base(collection)
    {
        dispatcher = Dispatcher.CurrentDispatcher;
        rwLock = new ReaderWriterLock();
    }

    protected override void InsertItem(int index, T item)
    {
        if (dispatcher.CheckAccess())
        {
            if (index > this.Count)
                return;
            LockCookie c = rwLock.UpgradeToWriterLock(-1);
            base.InsertItem(index, item);
            rwLock.DowngradeFromWriterLock(ref c);
        }
        else
        {
            object[] obj = new object[] { index, item };
            dispatcher.Invoke(
                DispatcherPriority.Send, 
                (SendOrPostCallback)delegate { InsertItemImpl(obj); }, 
                obj);
        }
    }
Run Code Online (Sandbox Code Playgroud)

然后我有一个视图模型类,它有一个执行保存的后台工作程序.

保存完成后,会向另一个视图模型触发事件以更新其列表.

    protected override void OnObjectAddedToRepository(object sender, ObjectEventArgs<cdAdministrators> e)
    {
        Dispatcher x = Dispatcher.CurrentDispatcher;
        var viewModel = new AdministratorViewModel(e.EventObject, DataAccess);
        viewModel.RecentlyAdded = true;
        viewModel.ItemSelected += this.OnItemSelected;
        this.AllViewModels.Add(viewModel);
        RecentlyAddedViewModel = viewModel;

        OnPropertyChanged(null);
    }
Run Code Online (Sandbox Code Playgroud)

两个列表都由单独的后台工作线程创建.

Jon*_*eet 7

如果您有代码将项添加到可观察集合(可能在视图模型中),Add请在调用中包装该Dispatcher.BeginInvoke调用.

不可否认,这意味着视图模型需要了解调度程序,然后测试变得笨拙......幸运的是,引入自己的IDispatcher接口并以正常方式使用依赖注入并不太难.