2011-07-04 26 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. 多個線程觸發事件,將數據添加到SortableBindingList

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

我試圖鎖定在SortableBindingList但仍然得到錯誤,搜索了很多,但無法找到一個解決方案。

回答

1

最後,我懷疑這是一個虛假的希望,使一個真正的線程安全綁定列表,將存在多個操作被執行的情況下 - 無論這是否是一個「檢查Count然後遍歷行數 - 1 」,或‘列舉與foreach’ - 有沒有簡單的方法來鎖定對這些的時間,因爲調用代碼是你的控制之外。

即使是半工作版本,你需要你的syncLock代碼添加到訪問,通過重寫所有可用的方法 - 但是,我看不到一個虛擬方法對於this[index]上的get,這可能會導致徒勞 - 只有在全部調用者同意使用鎖定時纔會同步。

最終,我懷疑試圖使用線程緊耦合的用戶界面是相當註定要失敗。海事組織,你可能有更多的成功分離的兩件事情,並具有約處理事件,並呼籲.Invoke(...)更新UI線程綁定的UI擔心。