Как я могу использовать Задачи в этом контексте? - PullRequest
4 голосов
/ 13 мая 2011
private void cmbPlatform_SelectedIndexChanged(object sender, EventArgs e)
{
    string platform = cmbPlatform.Text;
    UpcomingGameFinder gameFinder = new UpcomingGameFinder();
    Task.Factory.StartNew<IEnumerable<Game>>(() => gameFinder.FindUpcomingGamesByPlatform(platform))
        .ContinueWith((i) => PlaceGameItemsInPanel(i.Result));        
}

private void PlaceGameItemsInPanel(IEnumerable<Game> games)
{
    int yPosition = 0;
    foreach (var game in games)
    {
        GameItem item = new GameItem(game);
        item.Location = new Point(0, yPosition);
        panelGameItemsHolder.Controls.Add(item);
        yPosition += 125;
    }
}

Очевидно, что я делаю что-то не так, на мой взгляд, если я довольно плохо знаком с Задачами, поэтому я не уверен, как это будет работать в этом контексте.

По сути, FindUpcomingGames () занимает много времени для завершения, я хочу получить возвращенную коллекцию из этого метода, создать N количество объектов GameItem (которые являются пользовательскими элементами управления) и поместить их на панель, которая есть в моем Windows Формы.

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

Операция с поперечной резьбой недопустима: Элемент управления 'panelGameItemsHolder' доступ из потока, отличного от нить, в которой он был создан.

Есть предложения?

Ответы [ 3 ]

5 голосов
/ 13 мая 2011

Метод PlaceGameItemsInPanel должен переключать пользовательский интерфейс для взаимодействия с элементами пользовательского интерфейса. Самый простой способ сделать это, чтобы ваш ContinueWith происходил в потоке пользовательского интерфейса. т.е.

private void cmbPlatform_SelectedIndexChanged(object sender, EventArgs e)
{
    var uiContext = TaskScheduler.FromCurrentSynchronizationContext();
    string platform = cmbPlatform.Text;
    UpcomingGameFinder gameFinder = new UpcomingGameFinder();
    Task.Factory.StartNew<IEnumerable<Game>>(() => gameFinder.FindUpcomingGamesByPlatform(platform))
        .ContinueWith((i) => PlaceGameItemsInPanel(i.Result), uiContext);        
}    

Предполагается, что cmbPlatform_SelectedIndexChanged происходит в потоке пользовательского интерфейса (что произойдет, если он обрабатывает событие из поля со списком, как это, кажется, здесь). Таким образом, вы можете получить ссылку на текущий SynchronizationContext, а затем использовать его в ContinueWith, чтобы убедиться, что он работает на правильном SynchronizationContext.

Подробнее об этом можно прочитать на http://blogs.msdn.com/b/pfxteam/archive/2009/09/22/9898090.aspx

0 голосов
/ 13 мая 2011

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

0 голосов
/ 13 мая 2011

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

...