0

RefreshItemsViewModel のコンストラクターから呼び出され、ユーザーが希望するとき (RefreshCommandボタンのクリック時) に呼び出されます。

Delete も にバインドされDeleteCommandます。

他の方法では流動的ではないアニメーションがあるため、新しいスレッド内のアイテムを更新したいと思います。

したがって、バインディングはディスパッチャーのスレッドでは発生しませんが、削除は行われ、削除によって例外がスローされます (コードを参照)。

(XP をサポートする必要があるため、TPL (async/await) はオプションではありません。)

    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 に答える