0

RefreshItems从 ViewModel 的构造函数中调用,并且在用户希望时调用(RefreshCommand单击按钮)。

Delete 也绑定到一个DeleteCommand.

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

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

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

    public void RefreshItems()
    {
        new Thread(new ThreadStart(() =>
        {
            IsRefreshing = true;

            var items = _db.GetItems();

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

            Items = itemsCollectionView;

            IsRefreshing = false;
        })).Start();
    }

    private void Delete(ItemType item)
    {
        _db.DeleteItem(item);

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

        // InnerException: NotSupportedException
        // Message: This type of CollectionView does not support changes
        //          to its SourceCollection from a thread different from
        //          the Dispatcher thread.
        items.Remove(item);
    }
4

1 回答 1

2

我发现最好将数据绑定项视为 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);
}

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

于 2013-12-16T21:22:58.327 回答