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' 从除以外的线程访问 线程是在它上面创建的。
有什么建议吗?
答案 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()需要很长时间,你要么想尽早在后台启动它并缓存结果,要么重构它以便更快。在您现在使用任务时,您并不是真正异步工作。你刚刚开始一项任务,然后等待它完成。