8

INotifyPropertyChanged を実装するカスタム オブジェクトがあります。コレクションがBindingListに基づいているこれらのオブジェクトのコレクションがあります。コレクションのバインディングソースを作成し、バインディングソースとデータグリッドビューのデータソースを設定しました。

バックグラウンド スレッドからカスタム オブジェクトのプロパティを更新する必要があることを除いて、すべてがうまく機能します。そうすると、次のエラーが表示されます。

BindingSource を独自のデータ ソースにすることはできません。DataSource および DataMember プロパティを、BindingSource を参照する値に設定しないでください。

私は正確な問題(および解決策?)があるように見える次の投稿を見つけましたが、それを完全に理解することはできません.

http://social.msdn.microsoft.com/forums/en-US/winformsdatacontrols/thread/3566f7c7-eb47-422e-ab09-9549a18da360/

ビジネス オブジェクトのポストごとに oper 変数を作成して初期化し、2 つのイベント関数をコレクション クラスに入れました。これは正しくコンパイルされますが、実行すると例外なくハングします。

Invoke/Begin Invoke を使用するように言っている投稿をたくさん見てきましたが、UI で関数を呼び出しておらず、ビジネス オブジェクトを更新しているだけなので、invoke 呼び出しをどこに置くかわかりません。

1 つの制限: ビジネス オブジェクトが誰がそれを表示しているか (複数のコンシューマーが存在するため) を認識しないようにしたいので、GUI 参照をビジネス オブジェクトに送信して、後でそれらの参照を使用して呼び出しを呼び出せるようにすることはオプションではありません。

4

3 に答える 3

14

このクラスは、機能するフォーラムで見つけました。BindingList の代わりにこれを使用してください

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.ComponentModel;
using System.Threading;

namespace Utility
{
    public class ThreadedBindingList<T> : BindingList<T>
    {
        SynchronizationContext ctx = SynchronizationContext.Current;

        protected override void OnAddingNew(AddingNewEventArgs e)
        {

            if (ctx == null)
            {
                BaseAddingNew(e);
            }
            else
            {
                ctx.Send(delegate
                {
                    BaseAddingNew(e);
                }, null);
            }
        }
        void BaseAddingNew(AddingNewEventArgs e)
        {
            base.OnAddingNew(e);
        }
        protected override void OnListChanged(ListChangedEventArgs e)
        {
           // SynchronizationContext ctx = SynchronizationContext.Current;
            if (ctx == null)
            {
                BaseListChanged(e);
            }
            else
            {
                ctx.Send(delegate
                {
                    BaseListChanged(e);
                }, null);
            }
        }
        void BaseListChanged(ListChangedEventArgs e)
        {
            base.OnListChanged(e);
        }
    } 
}
于 2009-01-18T19:52:43.707 に答える
1

時間をかけて自分のニーズに合わせてサンプルをフォーマットしたので、読みやすいリファレンスとしてここに投稿したほうがよいでしょう。フォーマット以外は何も変わりません。

using System.ComponentModel; 
using System.Threading;

namespace Utility 
{
  public class ThreadedBindingList : BindingList 
  {
    SynchronizationContext ctx = SynchronizationContext.Current;
    protected override void OnAddingNew(AddingNewEventArgs e)
    {
      if (ctx == null)
      {
        BaseAddingNew(e);
      }
      else
      {
        ctx.Send(delegate { BaseAddingNew(e); }, null);
      }
    }

    void BaseAddingNew(AddingNewEventArgs e)
    {
      base.OnAddingNew(e);
    }

    protected override void OnListChanged(ListChangedEventArgs e)
    {
      // SynchronizationContext ctx = SynchronizationContext.Current;
      if (ctx == null)
      {
        BaseListChanged(e);
      }
      else
      {
        ctx.Send(delegate { BaseListChanged(e); }, null);
      }
    }

    void BaseListChanged(ListChangedEventArgs e)
    {
      base.OnListChanged(e);
    }
  }
}
于 2009-04-09T09:40:49.973 に答える
0

スレッド セーフとは言えませんが、上記の回答に対するこの小さな変更は、バックグラウンド スレッドがオブジェクト プロパティを表示よりも速く変更している場合に大きな影響を与える可能性があります。

protected override void OnListChanged(ListChangedEventArgs e)
{
  // SynchronizationContext ctx = SynchronizationContext.Current;
  if (ctx == null)
  {
    BaseListChanged(e);
  }
  else if(e.ListChangedType == ListChangedType.ItemChanged)
  {
    ctx.Post(delegate { BaseListChanged(e); }, null);
  }
  else
  {
    ctx.Send(delegate { BaseListChanged(e); }, null);
  }
}

同じオブジェクトが複数回変更された場合にポストされた呼び出しの数を減らし、ポストされたすべての呼び出しが処理されるまで後の send 呼び出しがブロックされるようにするための提案を歓迎します。

于 2014-10-14T03:41:08.860 に答える