7

ねえ、

私のアプリケーションでは、DataGrid を使用してデータを表示しています。スレッドですべてを機能させるためにAsyncObservableCollection、DataGrid の DataContext として使用しています。私のアプリケーションが起動すると、いくつかのフォルダーと update でファイルが検索されますAsyncObservableCollection。ファイルの検索は、別のスレッドで行われます。

Task.Factory.StartNew(() => _cardType.InitAllOrdersCollection())
    .ContinueWith((t) => ThrowEvent(), TaskContinuationOptions.None);

すべての読み込みロジックがInitAllOrdersCollection()メソッド内にある場所。

何らかの理由でアプリケーションを起動すると、コレクションに 1 つのアイテムがあり、フォルダーに 1 つのファイルしかない場合でも、DataGrid に同じデータを含む 2 つの行が表示されます。ファイルをロードする前に遅延 (Thread.Sleep()最小 50ms) を追加すると、DataGrid はすべてを正しく表示します (余分な行はありません)。ファイルをロードしているスレッド (で作成されたものTask.Factory.StartNew()) に遅延を追加する必要があります。

誰かが似たようなことに遭遇したことがありますか、それとも他に試してみるべきことがありますか? 前もって感謝します!

編集: 要求に応じていくつかのコードを追加:

public AsyncObservableCollection<IGridItem> OrdersCollection = new AsyncObservableCollection<IGridItem>();

public void InitAllOrdersCollection()
{
    // Thread.Sleep(50); <-- this sleep here fixes the problem!
    foreach (var convention in FileNameConventions)
    {
        var namePatterns = convention.NameConvention.Split(',');
        foreach (var pattern in namePatterns)
        {
            var validFiles = CardTypeExtensions.GetFiles(this.InputFolder, pattern, convention);
            if (validFiles.Any())
            {
                this.FilesToOrders(validFiles, convention);
            }
        }
    }
}

public static List<string> GetFiles(string inputFolder, string pattern, FileNameConvention convention)
{
    var files = Directory.GetFiles(inputFolder, pattern);
    return files.Where(file => IsCorrect(file, convention)).AsParallel().ToList();
}

// Adds new order to OrdersCollection if its not there already!
private void FilesToOrders(List<string> dirFiles, FileNameConvention convention)
{
    foreach (var dirFile in dirFiles.AsParallel())
    {
        var order = new Order(dirFile, this, convention);

        if (!this.OrdersCollection.ContainsOrder(order))
        {
                this.OrdersCollection.Add(order);
        }
    }
}

public static bool ContainsOrder(this ObservableCollection<IGridItem> collection, Order order)
{
    return collection.Cast<Order>().Any(c=>c.Filepath == order.Filepath);
}

FilesToOrders()メソッドは、新しい注文を に追加するものAsyncObservableCollectionです。お役に立てれば。

4

2 に答える 2

5

XAML ファイルに追加CanUserAddRows="False"する

<DataGrid CanUserAddRows="False"../>
于 2015-01-09T23:19:45.140 に答える
3

明らかな何かが欠けているかもしれAsyncObservableCollectionませんが、投稿したリンクの実装はスレッドセーフに見えません。

クリエーター (コンシューマー) スレッドで CollectionChanged / PropertyChanged イベントを発生させるコードが含まれていることがわかりますが、コレクション スレッド セーフの項目にアクセスするための同期は見られません。

アップデート

私が見る限り、同期なしで次のことを同時に行うことができます。

  • ワーカー (プロデューサー) スレッドがアイテムを挿入しています

  • UI (消費者) スレッドがアイテムを列挙している

1 つの可能性として、コンシューマー スレッドにアイテムを挿入するように変更することが考えられAsyncObservableCollection.InsertItemますSynchronizationContext.Sendが、これはもちろんパフォーマンスに影響します (プロデューサーは、コンシューマー スレッドが挿入を完了するのを待ってから続行します)。

別のアプローチはObservableCollection、コンシューマ スレッドでのみアクセスされる標準を使用SynchronizationContext.Postし、プロデューサー スレッドから挿入する項目を投稿するために使用することです。何かのようなもの:

foreach (var dirFile in dirFiles.AsParallel())
{
    var order = new Order(dirFile, this, convention);

    _synchronizationContext.Post(AddItem, order);

}

...

void AddItem(object item)
{
    // this is executed on the consumer thread
    // All access to OrderCollection on this thread so no need for synchnonization
    Order order = (Order) item;
    if (!OrdersCollection.ContainsOrder(order))
    {
        OrdersCollection.Add(order);
    }
}
于 2012-12-03T17:54:13.347 に答える