Wpf 额外线程中的绑定项不可从调度程序线程删除

Wpf 额外线程中的绑定项不可从调度程序线程删除,wpf,dispatcher,icollectionview,Wpf,Dispatcher,Icollectionview,RefreshItems是从ViewModel的构造函数调用的,并且是在用户需要时调用的(RefreshCommandon按钮单击) Delete还绑定到Delete命令 我想刷新一个新线程中的项目,因为有些动画不是流动的,否则 因此绑定不会发生在调度程序的线程上,但是删除会发生,并且删除会引发异常(请参见代码) (TPL(异步/等待)不是选项,因为必须支持XP。) public void RefreshItems() { 新线程(新线程开始(()=> { IsRefreshing=真; var

RefreshItems
是从ViewModel的构造函数调用的,并且是在用户需要时调用的(
RefreshCommand
on按钮单击)

Delete还绑定到
Delete命令

我想刷新一个新线程中的项目,因为有些动画不是流动的,否则

因此绑定不会发生在调度程序的线程上,但是删除会发生,并且删除会引发异常(请参见代码)

(TPL(异步/等待)不是选项,因为必须支持XP。)

public void RefreshItems()
{
新线程(新线程开始(()=>
{
IsRefreshing=真;
var items=_db.GetItems();
var itemsCollectionView=CollectionViewSource
.GetDefaultView(新的可观察集合(项));
Items=itemsCollectionView;
IsRefreshing=假;
})).Start();
}
私有无效删除(ItemType item)
{
_db.DeleteItem(项目);
var items=(observetecollection)items.SourceCollection;
//InnerException:NotSupportedException
//消息:此类型的CollectionView不支持更改
//从不同于的线程复制到其SourceCollection
//调度程序线程。
项目。移除(项目);
}

我发现最好将数据绑定项视为UI的一部分。因此,不应从后台线程访问任何数据绑定的内容

理想情况下,您的数据库访问应该使用类似EF6的东西,它支持异步方法。但是,由于您没有
async
数据库层,因此可以使用“伪异步”方法将(同步)数据库工作推送到后台线程上:

public async Task RefreshItemsAsync()
{
    IsRefreshing = true;

    var items = await Task.Run(() => _db.GetItems());

    var itemsCollectionView = CollectionViewSource
        .GetDefaultView(new ObservableCollection<ItemType>(items));

    Items = itemsCollectionView;

    IsRefreshing = false;
}

private async Task DeleteAsync(ItemType item)
{
    await Task.Run(() => _db.DeleteItem(item));

    var items = (ObservableCollection<ItemType>)Items.SourceCollection;

    items.Remove(item);
}
公共异步任务RefreshItemsAsync()
{
IsRefreshing=真;
var items=wait Task.Run(()=>_db.GetItems());
var itemsCollectionView=CollectionViewSource
.GetDefaultView(新的可观察集合(项));
Items=itemsCollectionView;
IsRefreshing=假;
}
专用异步任务DeleteAsync(ItemType item)
{
等待任务。运行(()=>_db.DeleteItem(item));
var items=(observetecollection)items.SourceCollection;
项目。移除(项目);
}

然而,这确实要求数据库层是线程无关的。如果它正在缓存一些数据库连接或绑定到特定线程的东西,那么这种方法将不起作用。

FYI,
Microsoft.Bcl.Async
在XP上工作,所以你可以在.NET 4.0上使用
Async
/
wait
。@StephenCleary太棒了!谢谢你的建议!顺便说一句,第三方物流也有同样的问题/例外。不过很高兴知道!你的问题没有快速的解决办法。理想情况下,应该使用
async
而不是从数据库加载线程,并且必须删除UI线程上的项目。如果您有太多的项目,那么您需要使用虚拟化。您所提到的正是不起作用的。异步刷新或在不同的线程中刷新是相同的(关于这个问题)。绑定发生在另一个(非UI)线程中,并导致不可删除的项。如果我只是简单地删除异步或线程的东西,它工作得很好,但动画会在实际工作完成后停止并开始。太棒了!我现在开始工作了,但我还有一些问题要问。你能回答我最后的问题吗?1.我不得不再次使用Task.Factory.StartNew(),因为Task.Run()不可用。与本机框架实现似乎有点不同?2.首先,我使用了async void,我知道它会被小心使用(或完全避免使用)。原因:我必须在构造函数中调用该方法。现在我再次将其重构为异步任务,并调用RefreshItemsAsync().Wait()。这是一个可以接受的方法吗?3.顺便说一句:异步代码的唯一区别(在我看来)是作用域(更小)。在
Microsoft.Bcl.async
中,
运行
TaskEx
类型上。构造函数不是使用
async void
Wait
IMO的充分理由;查看我在上的帖子,寻找替代方案。非常感谢你,斯蒂芬!
public async Task RefreshItemsAsync()
{
    IsRefreshing = true;

    var items = await Task.Run(() => _db.GetItems());

    var itemsCollectionView = CollectionViewSource
        .GetDefaultView(new ObservableCollection<ItemType>(items));

    Items = itemsCollectionView;

    IsRefreshing = false;
}

private async Task DeleteAsync(ItemType item)
{
    await Task.Run(() => _db.DeleteItem(item));

    var items = (ObservableCollection<ItemType>)Items.SourceCollection;

    items.Remove(item);
}