2011-07-04 4 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, 인덱스가 범위를 벗어났습니다. 오류, thread-Safe로 만드는 방법?

인덱스 범위를 벗어난 것입니다. 음수가 아니어야하며 콜렉션의 크기보다 작아야합니다. 매개 변수 이름 : 인덱스

  1. SortableBindingList이 DataGridView에 바인딩되어, 가상 모드
  2. 다중 스레드 내가 잠 시도

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

SortableBindingList에 데이터를 추가 이벤트를 발생 SortableBindingList하지만 여전히 오류가 발생하고 많이 검색했지만 해결책을 찾을 수 없습니다.

답변

1

궁극적으로 나는 다중 스레드 연산이 수행되는 경우가 있기 때문에 궁극적으로 스레드 안전 바인딩 목록을 만드는 것은 잘못된 희망이라고 생각합니다. "수를 확인한 다음 Count-1 행을 반복합니다 "또는"foreach과 함께 열거하십시오. "- 지속 시간을 잠 그려면 쉬운 방법이 없습니다. 호출 코드가 사용자의 제어 범위를 벗어 났기 때문입니다. 그러나, 나는 가상 방법을 볼 수 없습니다 - 모든 가능한 방법

에도 반 가공 버전, 당신은 를 오버라이드 (override)를 통해, 모든에 액세스 할 syncLock 코드를 추가해야 것 getthis[index] 인 경우 으로 표시 될 수 있습니다. 모두 발신자가 잠금 장치를 사용하는 데 동의하는 경우에만 동기화됩니다.

궁극적으로, 나는 단단한 UI 커플 링으로 스레딩을 사용하려고 시도하는 것이 상당히 파멸 할 것이라고 생각합니다. IMO를 사용하면 두 가지를 분리하고 UI에서 이벤트를 처리하는 것에 대해 걱정하고 .Invoke(...)을 호출하여 UI 스레드의 바인딩을 업데이트하는 데 더 많은 성공을 거둘 수 있습니다.

관련 문제