问题:从线程访问表单及其控件时,哪个更合适?:
调用表单并通过表单调用更新其控件
明确调用控件并明确更新控件
代码
if (mainForm.InvokeRequired)
{
mainForm.Invoke(
(Action)(() =>
{
mainForm.label1.Text = "update";
mainForm.textBox1.Text = "update";
mainForm.button1.Text = "update";
}));
}
else
{
mainForm.label1.Text = "update";
mainForm.textBox1.Text = "update";
mainForm.button1.Text = "update";
}
//OR
if (mainForm.label1.InvokeRequired)
{
mainForm.Invoke((Action)(() => { mainForm.label1.Text = "update"; }));
}
else
{
mainForm.label1.Text = "update";
}
答案 0 :(得分:0)
每次Invoke
时,都会存在延迟和成本,因为我们必须向UI线程发送消息,该消息实质上是“请运行此代码”。然后,我们必须等待UI线程接收到此消息(当前可能正在忙于其他工作),运行我们要求它执行的代码,并指示它已经完成了。然后,最后,我们可以在Invoke
调用之后恢复工作。
现在,在宏大的计划中,这一成本是相当低的。因此,如果您仅使用Invoke
一次或两次,则不值得考虑。但是,如果您打算执行一个大循环并在循环内进行Invoke
,则可能需要暂停并重新考虑。通常最好将Invoke
移到循环之外。
但是,UI线程是宝贵的资源。我们不想花时间在该线程上执行 non 与UI相关的任务。
因此,如果您有一个循环执行CPU密集型工作和UI更新的混合操作,那么两者都不是必须的。在这种情况下,请查看是否可以重新构造代码,以便在循环内准备UI更新的批次,然后偶尔(或在循环之后,如果可能的话)执行Invoke
只是执行这些UI更新。
在您的情况下,您似乎已经执行了一批UI更新。因此,更喜欢Invoke
一次执行全部三个操作的代码:
if (mainForm.InvokeRequired)
{
mainForm.Invoke(
(Action)(() =>
{
mainForm.label1.Text = "update";
mainForm.textBox1.Text = "update";
mainForm.button1.Text = "update";
}));
}
else
{
mainForm.label1.Text = "update";
mainForm.textBox1.Text = "update";
mainForm.button1.Text = "update";
}
但是请注意,通常最好对代码进行结构化,以免与上面的实际UI更新重复。像这样:
private void DoUpdate()
{
if(mainForm.InvokeRequired)
{
mainForm.Invoke(DoUpdate);
return;
}
mainForm.label1.Text = "update";
mainForm.textBox1.Text = "update";
mainForm.button1.Text = "update";
}
答案 1 :(得分:0)
我通常使用ISynchronizeInvoke,因为所有表单/用户控件都继承了此接口,然后调用一种方法来对ui线程执行操作(如果需要调用),
public void SafeExecute(IView form, Action methodToExecute)
{
// args chek....
ISynchronizeInvoke view = form as ISynchronizeInvoke;
if(view != null)
{
if (!View.InvokeRequired)
{
methodToExecute();
}
else
{
view.Invoke(methodToExecute, null);
}
}
else methodToExecute();
}
然后在您的代码后面,您可以像这样调用此方法(我假设您的视图实现了一个接口,在这种情况下,我将其称为IView)
SafeExecute(this, () => {
mainForm.label1.Text = "update";
mainForm.textBox1.Text = "update";
mainForm.button1.Text = "update";
})