Инкрементальная загрузка элементов в списке

Я взял следующий пример из MSDN для постепенной загрузки миниатюр в виде списка в приложении WinRT:

https://code.msdn.microsoft.com/windowsapps/Data-Binding-7b1d67b5

Я хотел бы удалить строку «ожидание Task.Delay (10)» ниже. Когда я это делаю, я получаю предупреждение о том, что в методе отсутствует оператор ожидания.

protected async override Task<IList<object>> LoadMoreItemsOverrideAsync(System.Threading.CancellationToken c, uint count)
        {
            uint toGenerate = System.Math.Min(count, _maxCount - _count);

            // Wait for work 
            await Task.Delay(10);

            // This code simply generates
            var values = from j in Enumerable.Range((int)_count, (int)toGenerate)
                         select (object)_generator(j);
            _count += toGenerate;

            return values.ToArray();
        }

Я попытался переписать метод и обернуть весь метод в задачу следующим образом:

protected async override Task<IList<object>> LoadMoreItemsOverrideAsync(System.Threading.CancellationToken c, uint count)
            {
     return await  Task.Run(() => {
                uint toGenerate = System.Math.Min(count, _maxCount - _count);

                // This code simply generates
                var values = from j in Enumerable.Range((int)_count, (int)toGenerate)
                             select (object)_generator(j);
                _count += toGenerate;

                return values.ToList<object>();
            });
}

Однако я получаю исключения потоков:

Исключение: приложение вызвало интерфейс, который был маршалирован для другого потока. (Исключение из HRESULT: 0x8001010E (RPC_E_WRONG_THREAD))

Кажется, мне нужно запустить это в потоке пользовательского интерфейса? Но у меня нет доступа к диспетчеру.

Ищу некоторые рекомендации


person user82383    schedule 29.05.2015    source источник
comment
Разве в элементе управления нет метода Invoke(delegate)?   -  person Pieter Geerkens    schedule 29.05.2015


Ответы (1)


Я думаю, вы ищете не в том месте. Конечно, я делаю небольшой удар в темноте, но, поскольку остальное выглядит безобидно, что-то в вашем методе _generator(int), скорее всего, должно выполняться в потоке пользовательского интерфейса. (Возможно, это не поток пользовательского интерфейса сам по себе, но что-то нужно запустить в том же потоке, что и что-то еще. Поскольку вы упомянули эскизы, наиболее вероятной причиной является то, что у вас есть объект GDI+ Graphics, созданный в один поток и пытаются манипулировать им в другом.)

Мое предложение состоит в том, чтобы внимательно изучить ваш метод _generator(int) и создать его версию async, которая позаботится о том, чтобы код выполнялся в правильном потоке. Таким образом поддерживается инкапсуляция, и вашему обратному вызову LoadMoreItemsOverrideAsync не нужно ничего понимать о внутренней работе _generator.


В качестве примечания, добавление задержки в 10 мс почти наверняка не является правильным действием, если только вы не пытаетесь активно избежать какого-либо состояния гонки. (Что означает «ожидание работы» в комментарии? Если вы действительно ждете работы, разве вы не должны ждать завершения другой задачи, а не произвольных 10 мс?)

Предупреждение, которое вы, скорее всего, получаете, пытается сказать вам: «Вы пометили этот метод ключевым словом async, но в нем нет ничего асинхронного. Вы где-то забыли await

Если в крайнем случае у вас нет выбора, кроме синхронного запуска кода, сделайте именно это. Поместите туда комментарий и подтвердите ситуацию, отключив это конкретное предупреждение для метода.

person lc.    schedule 29.05.2015