Посредством обновления / решения ... Я следовал * решению Хенка (вроде), так что я сохраняю очередь объектов рабочих элементов, но все еще обрабатываю их с помощью ThreadPool. Выбранные элементы «выталкиваются», помещая их в начало очереди (а не в конец) [примечание: для этого нужна специальная коллекция].
Следующее может описать это подробно (вместо кода)
- Изменено
Customer
, чтобы сохранить свойство IList<Account>
с именем KnownValues , а также объект, используемый для блокировки с именем KnownValuesSyncObject (поскольку я хочу, чтобы KnownValues были нулевыми, когда они отсутствуют. пока не известно).
- Форма поиска поддерживает переменную экземпляра
Deque<CustomerAccountLoadingWorkItem>
(из PowerCollections )
- A
CustomerAccountLoadingWorkItem
содержит ссылку на клиента, для которого он предназначен, а также на ManualResetEvent
дескриптор, с которым он был создан.
- Чтобы начать загрузку только для видимых элементов (т. Е. Не прокручивать с экрана), я использовал ответы из моего другого поста , чтобы использовать виртуализацию данных в качестве механизма организации очередей CustomerAccountLoadingWorkItem, поскольку каждая «страница» была загружена , Сразу после добавления в очередь рабочих элементов задача добавляется в очередь ThreadPool. Контекстом / состоянием для вызова
ThreadPool.QueueUserWorkItem
была моя очередь _accountLoadingWorkItems.
- Делегат WaitCallback, запущенный ThreadPool, взял переданную ему очередь рабочего элемента, затем (с помощью блокировок) снял с обработки верхний элемент (если его не было, затем сразу же вернулся); затем обработал этот элемент. Используемая функция была статической функцией как часть CustomerAccountLoadingWorkItem, так что она могла получить доступ к своему частному состоянию только для чтения (то есть, Customer и ManualResetEvent)
- В конце обработки функция статической обработки также устанавливает Customer.KnownValues (используя для блокировки KnownValuesSyncObject).
- Когда пользователь выбрал значение в сетке «Клиенты», в его уже отдельном потоке (через BackgroundWorker), если
Customer.KnownValues
еще не заполнен (то есть он, вероятно, где-то находится в очереди), он добавляет новый CustomerAccountLoadingWorkItem. в очередь рабочих элементов (но вверху !!! [именно поэтому требовалась Deque]), а также добавляет новую задачу обработки в ThreadPool. Затем, поскольку он создал рабочий элемент, он вызывает ManaulResetEvent.WaitOne()
, чтобы вызвать ожидание завершения задачи пула потоков.
Надеюсь, это имело смысл ...
Следует отметить, что, поскольку мое решение по-прежнему использует ThreadPool, когда пользователь выбирает элемент, который мне все еще приходится ждать, пока не завершится текущий поток потоков пула, прежде чем мой рабочий элемент будет поднят, я подумал, что это нормально и, возможно, даже желательно видеть как будто ресурсы, используемые для запроса учетных записей (веб-службы), будут частично заблокированы, в любом случае они, вероятно, будут работать одинаково быстро (из-за плохой архитектуры и общего прокси-сервера веб-службы).
В целом, я, безусловно, сделал то, что должно было быть легкой задачей, несколько сложнее, и если бы я мог использовать Framework 4, я бы наверняка посмотрел на путь TPL.