2011-07-04 15 views
0
using System; 
using System.Collections.Generic; 
using System.ComponentModel; 

namespace MyApplication 
{ 
    public class SortableBindingList<T> : BindingList<T> 
    { 
     private static object syncLock = new object(); 
     private readonly Dictionary<Type, PropertyComparer<T>> comparers; 
     private bool isSorted; 
     private ListSortDirection listSortDirection; 
     private PropertyDescriptor propertyDescriptor; 

     private System.ComponentModel.ISynchronizeInvoke _SyncObject; 
     private System.Action<System.ComponentModel.ListChangedEventArgs> _FireEventAction; 

     public SortableBindingList() 
      : base(new List<T>()) 
     { 
      this.comparers = new Dictionary<Type, PropertyComparer<T>>(); 
     } 

     public SortableBindingList(IEnumerable<T> enumeration, System.ComponentModel.ISynchronizeInvoke syncObject) 
      : base(new List<T>(enumeration)) 
     { 
      _SyncObject = syncObject; 
      _FireEventAction = FireEvent; 

      this.comparers = new Dictionary<Type, PropertyComparer<T>>(); 
     } 

     protected override bool SupportsSortingCore 
     { 
      get { return true; } 
     } 

     protected override bool IsSortedCore 
     { 
      get { return this.isSorted; } 
     } 

     protected override PropertyDescriptor SortPropertyCore 
     { 
      get { return this.propertyDescriptor; } 
     } 

     protected override ListSortDirection SortDirectionCore 
     { 
      get { return this.listSortDirection; } 
     } 

     protected override bool SupportsSearchingCore 
     { 
      get { return true; } 
     } 

     protected override void InsertItem(int index, T item) 
     { 
      lock (syncLock) 
      { 
       base.InsertItem(index, item); 
      } 
     } 

     protected override void ApplySortCore(PropertyDescriptor property, ListSortDirection direction) 
     { 
      List<T> itemsList = (List<T>)this.Items; 

      Type propertyType = property.PropertyType; 
      PropertyComparer<T> comparer; 
      if (!this.comparers.TryGetValue(propertyType, out comparer)) 
      { 
       comparer = new PropertyComparer<T>(property, direction); 
       this.comparers.Add(propertyType, comparer); 
      } 

      comparer.SetPropertyAndDirection(property, direction); 
      itemsList.Sort(comparer); 

      this.propertyDescriptor = property; 
      this.listSortDirection = direction; 
      this.isSorted = true; 

      this.OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1)); 
     } 

     protected override void RemoveSortCore() 
     { 
      this.isSorted = false; 
      this.propertyDescriptor = base.SortPropertyCore; 
      this.listSortDirection = base.SortDirectionCore; 

      this.OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1)); 
     } 

     protected override int FindCore(PropertyDescriptor property, object key) 
     { 
      int count = this.Count; 
      for (int i = 0; i < count; ++i) 
      { 
       T element = this[i]; 
       if (property.GetValue(element).Equals(key)) 
       { 
        return i; 
       } 
      } 

      return -1; 
     } 

     protected override void OnListChanged(System.ComponentModel.ListChangedEventArgs args) 
     { 
      lock (syncLock) 
      { 
       if (_SyncObject == null) 
       { 
        FireEvent(args); 
       } 
       else 
       { 
        _SyncObject.Invoke(_FireEventAction, new object[] { args }); 
       } 
      } 
     } 

     private void FireEvent(System.ComponentModel.ListChangedEventArgs args) 
     { 
      base.OnListChanged(args); 
     } 
    } 
} 

私は、次のエラーを取得しています:SortableBindingList、インデックスが範囲外です。エラー、スレッドセーフな方法

インデックスが範囲外でした。負でなく、コレクションのサイズより小さくなければなりません。 パラメータ名:インデックス

  1. SortableBindingListがDataGridViewのにバインドされ、仮想モード
  2. 複数のスレッドが、私がロックしようとした

private void ProxyScraper_OnProxyFound(Proxy Proxy, int Count) 
{  
    ProxyProcessedCount.Text = Count.ToString(); 
    _ProxyList.Add(Proxy); 
} 

SortableBindingListにデータを追加し、イベントを発生させますSortableBindingListでもまだエラーが発生していますが、多くは検索されていますが解決策を見つけることができません。

答えて

1

最終的には、本当にスレッドセーフなバインディングリストを作成することは間違いないと思う。複数の操作が実行されるケースがあるため、「CountをチェックしてからCount-1に行を繰り返す"、" enumerate with foreach "のようになります。の間で簡単にロックする方法はありません。は、呼び出しコードがコントロール外にあるためです。

でもハーフ作業バージョンのために、あなたはにごsyncLockコードを追加する必要があると思い、すべてアクセス、すべて利用可能なメソッドをオーバーライドすることを経由して - しかし、私は仮想メソッドを見ることができませんgetthis[index]の場合、となります。すべて発信者がロックを使用することに同意する場合にのみ同期化されます。

最終的に、私は、きついUIカップリングでスレッドを使用しようとするとかなりの運命にあると考えています。 IMOを使用すると、2つの事柄を分離してより多くの成功を収め、イベントを処理するUIを心配し、.Invoke(...)を呼び出してUIスレッドのバインディングを更新することができます。

関連する問題