7

ObservableCollection は、UI スレッドからの追加、削除、クリア操作のみをサポートしているようです。NO UI スレッドによって操作された場合、Not Support Exception がスローされます。ObservableCollection のメソッドをオーバーライドしようとしましたが、残念ながら多くの問題に遭遇しました。マルチスレッドで操作できる ObservableCollection サンプルを提供してくれる人はいますか? どうもありがとう!

4

4 に答える 4

7

Kentが提供するリンクを使用すると、次のコードを使用してスレッド間でコレクションを変更できます。

while (!Monitor.TryEnter(_lock, 10))
{
   DoEvents();
}

try
{
   //modify collection
}
finally
{
   Monitor.Exit(_lock);
}

ただし、元のスレッドでコレクションを変更するだけの場合は、UI スレッドへのコールバックを使用してみてください。私は通常、次のようなことをします:

this.Dispatcher.Invoke(new MyDelegate((myParam) =>
{
  this.MyCollection.Add(myParam);
}), state);
于 2008-10-09T12:43:23.120 に答える
3

これらの操作を実行するには、基本的にUIスレッドに対してInvokeまたはBeginInvokeを実行する必要があります。

Public Delegate Sub AddItemDelegate(ByVal item As T)

Public Sub AddItem(ByVal item As T)
    If Application.Current.Dispatcher.CheckAccess() Then
        Me.Add(item)
    Else
        Application.Current.Dispatcher.Invoke(Threading.DispatcherPriority.Normal, New AddItemDelegate(AddressOf AddItem), item)
    End If
End Sub
于 2008-10-09T12:47:23.470 に答える
3

個人的には、マークの回答スタイルよりもボブの回答スタイルの方が使いやすいと思います。これを行うための C# WPF スニペットを次に示します。

  1. クラスのコンストラクターで、監視可能なコレクションを作成するときに現在のディスパッチャーを取得します。ご指摘のとおり、元のスレッドで変更を行う必要があるため、メインのGUI スレッドではない可能性があります。したがって、Application.Current.Dispatcherは常に正しいわけではなく、すべてのクラスにthis.Dispatcherがあるわけではありません。

    _dispatcher = System.Windows.Threading.Dispatcher.CurrentDispatcher;
    _data = new ObservableCollection<MyDataItemClass>();
    
  2. ディスパッチャを使用して、元のスレッドが必要なコード セクションを呼び出します。

    _dispatcher.Invoke(new Action(() => { _data.Add(dataItem); }));
    

それはあなたのためにトリックをするはずです。.Invokeの代わりに.BeginInvokeを好む状況もありますが。

于 2012-11-14T23:54:22.807 に答える
2

おそらくこれに対する私の答えを調べたいと思うかもしれませんがplease note、コードはここから来たものであり、私にクレジットすることはできません. 私はVBでそれを実装しようとしましたが。:元のサイト

これを使用して、ObservableCollectionEx がアクセス データベースから非同期に取り込まれたクラスから WPF リストボックスを取り込んだ。それは機能します。

public class ObservableCollectionEx<T> : ObservableCollection<T>
{
   // Override the event so this class can access it
   public override event System.Collections.Specialized.NotifyCollectionChangedEventHandler    
 CollectionChanged;

   protected override void OnCollectionChanged    (System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
   {
  // Be nice - use BlockReentrancy like MSDN said
  using (BlockReentrancy())
  {
     System.Collections.Specialized.NotifyCollectionChangedEventHandler eventHandler = CollectionChanged;
     if (eventHandler == null)
        return;

     Delegate[] delegates = eventHandler.GetInvocationList();
     // Walk thru invocation list
     foreach (System.Collections.Specialized.NotifyCollectionChangedEventHandler handler in delegates)
     {
        DispatcherObject dispatcherObject = handler.Target as DispatcherObject;
        // If the subscriber is a DispatcherObject and different thread
        if (dispatcherObject != null && dispatcherObject.CheckAccess() == false)
        {
           // Invoke handler in the target dispatcher's thread
           dispatcherObject.Dispatcher.Invoke(DispatcherPriority.DataBind, handler, this, e);
        }
        else // Execute handler as is
           handler(this, e);
     }
  }
}
}
于 2013-01-12T21:20:51.430 に答える