我已经搜索了高低,用于调用堆栈溢出所需的相关帖子..它帮助我学到了很多...但我有几个问题..不仅涉及调用所需,还有背景工作者..忍受我请.. :))
我的应用程序做了很长时间,需要在进程中更新gui(进度条,状态栏,文本框)..我使用了一个线程,但在更新UI时它给出了可怕的跨线程异常..我最近(有点)得到正确使用invokerequired的悬念.. [Automating the InvokeRequired code pattern] ..我在这篇文章中使用的代码是:
public static partial class CHelper
{
public static void InvokeIfRequired(this Control oCtrl, MethodInvoker fnAction)
{
if (oCtrl.InvokeRequired)
{
oCtrl.Invoke(fnAction);
}
else
{
fnAction();
}
}
}
public partial class Form1 : Form
{
public void Test()
{
this.InvokeIfRequired(() =>
{
Text = "Window Title";
button1.Text = "Hello";
});
button1.InvokeIfRequired(() =>
{
Text = "Window Title";
button1.Text = "Hello";
});
}
}
现在这里有一些我注意到的.. this.InvokeIfRequired和button1.InvokeIfRequired都做同样的事情..为什么会这样?我期待button1.InvokeIfRequired中的文本对应于button1的文本属性..但是它引用了父窗体的..对我来说这看起来很傻,不直观,错误......或者可能是我做错了什么......
另一个问题..我当时没有得到invokerequired的挂起所以我使用后台工作者..并使用进度事件来更新gui ..
public partial class Form1 : Form
{
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
backgroundWorker1.ReportProgress(0, "Hello World");
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
if (e.UserState != null)
{
button1.Text = e.UserState as string;
}
}
}
到目前为止,它还没有给我带来麻烦..我想知道这两种方法中的哪一种更好?为什么?还有,有没有办法将数据传递给流行的InvokeIfRequired函数?
谢谢.. =)
编辑01:Is there any difference between using Invoke for the parent form or for the target control? ..是form.invoke和control.invoke是一样的......但为什么会这样呢?它不直观,给人错误的印象。
答案 0 :(得分:0)
嗯,对于Button控件来说根本不重要。 Windows有一个硬规则,即窗口的所有子窗口必须由同一个线程拥有。因此,通过该规则,表单和按钮的Begin / Invoke()方法将封送对正确线程的调用。
请注意,当您需要更新没有Handle属性的组件的属性时,它会变得很尴尬。像ToolStripButton一样。现在你拥有来选择另一个控件。所以赞成一致性并始终使用表格。
当然,请支持BackgroundWorker。它有一个诀窍,可以通过限制你射脚的方式来帮助你做到这一点。