如何在此上下文中使用任务?

时间:2011-05-13 14:17:39

标签: c# .net task task-parallel-library

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 个答案:

答案 0 :(得分:5)

PlaceGameItemsInPanel方法需要切换UI以与UI项交互。最简单的方法是在UI线程上进行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正在UI线程上发生(如果它正在处理来自组合框的事件,它就会出现,因为它似乎在这里)。因此,您可以获取对当前SynchronizationContext的引用,然后在ContinueWith中使用它以确保在正确的SynchronizationContext上运行。

您可以在http://blogs.msdn.com/b/pfxteam/archive/2009/09/22/9898090.aspx

了解详情

答案 1 :(得分:0)

您可以在.ContinueWith委托中完成工作...在创建对象后,将其添加到某个集合(理想情况下是可观察集合),这将自动更新UI。当然,如果你不使用绑定的可观察集合,你必须自己更新UI控件(只需要小心跨线程通信)

答案 2 :(得分:0)

您正在使用这些任务,但我认为您可能需要重新考虑您的工作流程。如果FindUpcomingGames()需要很长时间,你要么想尽早在后台启动它并缓存结果,要么重构它以便更快。在您现在使用任务时,您并不是真正异步工作。你刚刚开始一项任务,然后等待它完成。