SortableBindingList, Индекс был вне диапазона Ошибка, как сделать его потокобезопасным? - PullRequest
0 голосов
/ 04 июля 2011
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);
        }
    }
}

Я получаю следующую ошибку:

Индекс был вне диапазона.Должен быть неотрицательным и меньшим, чем размер коллекции.Имя параметра: index

  1. SortableBindingList привязан к DataGridView, виртуальный режим
  2. Многопоточное событие, которое добавляет данные в SortableBindingList

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

Я пытался заблокировать SortableBindingList, но все еще получал ошибку, много искал, но не смог найти решение.

1 Ответ

1 голос
/ 04 июля 2011

В конечном счете, я подозреваю, что создание ложного поточно-связывающего списка является ложной надеждой, так как будут случаи, когда выполняется несколько операций - независимо от того, является ли это «проверкой счетчика, затем итерацией строк в счетчик-1»или «перечислите с foreach» - и нет простого способа заблокировать длительность из них, поскольку вызывающий код находится вне вашего контроля.

Даже на половинурабочей версии, вам нужно будет добавить свой код syncLock к при каждом доступе, переопределив все доступные методы -однако, я не вижу виртуального метода для get на this[index], который мог бы сделать бесполезным - он синхронизируется, только если все вызывающие согласны использовать блокировку.

В конечном счете, я подозреваю, что попытка использовать многопоточность с жесткой связью пользовательского интерфейса довольно обречена.IMO, вы можете добиться большего успеха, разделяя эти две вещи и заставляя пользовательский интерфейс беспокоиться об обработке события и вызывая .Invoke(...), чтобы обновить привязку в потоке пользовательского интерфейса.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...