我正在做一些MultiThreading但是表格在加载时暂停。
我正在尝试显示表单,然后在后台它应该填充组合框而不会暂停表单。
在我的Form_Load事件中,我有这个:
private void frmIni_Load(object sender, EventArgs e)
{
Application.DoEvents();
Thread threadOne = new Thread(GetServers);
threadOne.Start();
}
在我的GetServers()方法中:
private void GetServers()
{
cboServer.BeginInvoke(
(Action)(() => {
servers = SmoApplication.EnumAvailableSqlServers(false);
Thread.Sleep(1);
foreach (DataRow server in servers.Rows)
{
cboServer.Properties.Items.Add(server["Name"]);
Thread.Sleep(1);
}
}));
}
我在这里缺少什么?表单不应该暂停,它应该工作,然后最终当线程完成时,它应该只填充组合框。
答案 0 :(得分:6)
是的,因此它阻止UI的原因很简单,因为在新线程中没有运行真正的代码。在你对GetServers
的调用中,你回调到UI线程,然后做忙碌的事情(你可能根本不在这里使用线程......)。
你想在线程中放置任何长时间运行的工作,并且当你想要更新它时只回调到UI线程,例如。
private void frmIni_Load(object sender, EventArgs e)
{
Task.Factory.StartNew(() => {
return SmoApplication.EnumAvailableServers(false);
}).ContinueWith((task) => {
foreach (var server in task.Result)
{
cboServer.Properties.Items.Add(server["Name"]);
}
}, TaskScheduler.FromCurrentSynchronizationContext());
}
注意事项
DoEvents
,尤其是当您不理解usage时。{/ li>
Thread.Sleep
来模拟“暂停”(您似乎正在进行此操作)答案 1 :(得分:1)
由于BeginInvoke
,所有代码都在UI线程上执行。
private void GetServers()
{
servers = SmoApplication.EnumAvailableSqlServers(false);
Thread.Sleep(1); // Why?
cboServer.BeginInvoke(
(Action)(() => {
foreach (DataRow server in servers.Rows)
{
cboServer.Properties.Items.Add(server["Name"]);
Thread.Sleep(1); // Why?
}
})
);
}
答案 2 :(得分:1)
首先:创建一个Thread将消耗少量时间。此外,您将使用BeginInvoke
cboServer.BeginInvoke(
(Action)(() => {
servers = SmoApplication.EnumAvailableSqlServers(false);
Thread.Sleep(1);
foreach (DataRow server in servers.Rows)
{
cboServer.Properties.Items.Add(server["Name"]);
Thread.Sleep(1);
}
})
);
您应该尝试将除UI更新之外的所有内容移出BeginInvoke委托,不知何故如下:
private void GetServers()
{
servers = SmoApplication.EnumAvailableSqlServers(false);
cboServer.BeginInvoke(
(Action)(() => {
foreach (DataRow server in servers.Rows)
{
cboServer.Properties.Items.Add(server["Name"]);
}
}));
}
答案 3 :(得分:0)
这是针对您的场景/情况执行此操作的正确方法。
你应该在线程池上创建一个线程并让它进行线程管理。此外,当您的线程被池踢出/调用时,一旦获得所有SQL Server,您就可以通过开始调用添加到组合框中,这样您就可以在UI线程和当前线程之间正确切换以更新组合框。
Threadpool:
http://msdn.microsoft.com/en-us/library/vstudio/kbf0f1ct(v=vs.100).aspx
在游泳池调用的方法中,通过执行begininvoke将项目添加到组合框中。
更新 - 我看到@James几乎发布了我的建议。伟大的思想相似。
答案 4 :(得分:0)
尽管答案很严重,但您的代码仍然无法按预期工作:
private void GetServers()
{
servers = SmoApplication.EnumAvailableSqlServers(false);
// Thread.Sleep(1);
foreach (DataRow server in servers.Rows)
{
cboServer.BeginInvoke((Action)(() => { cboServer.Properties.Items.Add(server["Name"]);}));
// Thread.Sleep(1);
}
}