C# 时代。如果代码可以在显示控件之前执行,或者出现致命的异常,则必须使用InvokeRequired。也许我太笨了,但这段代码无法编译。所以我按照自己构建的方式(VS2008)修复了它。只是为了完整性:在WPF中有一种不同的调度机制,但它的工作原理相当类似。您
C# 时代。如果代码可以在显示控件之前执行,或者出现致命的异常,则必须使用InvokeRequired。也许我太笨了,但这段代码无法编译。所以我按照自己构建的方式(VS2008)修复了它。只是为了完整性:在WPF中有一种不同的调度机制,但它的工作原理相当类似。您,c#,multithreading,winforms,thread-safety,invokerequired,C#,Multithreading,Winforms,Thread Safety,Invokerequired,时代。如果代码可以在显示控件之前执行,或者出现致命的异常,则必须使用InvokeRequired。也许我太笨了,但这段代码无法编译。所以我按照自己构建的方式(VS2008)修复了它。只是为了完整性:在WPF中有一种不同的调度机制,但它的工作原理相当类似。您可以在那里使用这个扩展方法:publicstaticvoid invokeFrequered(这个T ataTarget,Action aActionToExecute),其中T:DispatcherObject{if(ataTarget.Ch
时代。如果代码可以在显示控件之前执行,或者出现致命的异常,则必须使用
InvokeRequired
。也许我太笨了,但这段代码无法编译。所以我按照自己构建的方式(VS2008)修复了它。只是为了完整性:在WPF中有一种不同的调度机制,但它的工作原理相当类似。您可以在那里使用这个扩展方法:publicstaticvoid invokeFrequered(这个T ataTarget,Action aActionToExecute),其中T:DispatcherObject{if(ataTarget.CheckAccess()){aActionToExecute(ataTarget);}else{ataTarget.Dispatcher.Invoke(aActionToExecute);}我添加了一个答案,稍微简化了Lee的解决方案。嗨,当我使用类似的东西时,这个通用实现可能会产生一个大问题。如果控件是Disposition/Disposed,您将得到一个ObjectDisposedException。@Offler-如果它们是在不同的线程上处理的,那么您有一个同步问题,这不是此方法中的问题。使用ISynchronizeInvoke
而不是Control
不是更好吗?(向Jon Skeet致敬)@mike de clerk,我很关心你关于在(!control.Visible)…sleep..时添加的建议。对我来说,这有一种糟糕的代码味道,因为它是一种潜在的无限延迟(在某些情况下甚至是无限循环),在代码中可能有调用方不希望出现这种延迟(甚至是死锁)。依我看,Sleep
的任何使用都应由每个调用者负责,或者应该放在一个单独的包装中,并清楚地标明其后果。通常,最好是“硬失败”(异常,在测试期间捕获),或者在控件未准备好时“不做任何事情”。注释?while(!Visible)需要超时。错误的做法可能导致难以调试的无限循环。事实并非如此,因为我们正在调用winforms控件。另请参见@OlivierJacot Descombes,如果您能解释thread.invokerequired背后是如何工作的,那就太好了。嘿,谢谢您的回答。我问这个问题已经好几年了(和我和C#一起工作的时间差不多一样长),但我想知道你是否可以进一步解释一下?您链接到的文档引用了在控件被赋予句柄之前调用invoke()
等的特定危险,但IMHO没有描述您所描述的内容。所有这些invoke()
废话的全部要点是以线程安全的方式更新UI,我认为在阻塞上下文中放置更多指令会导致口吃?(呃……很高兴我停止使用M$tech。太复杂了!)我还想指出,尽管经常使用原始代码(早在那时),但我没有注意到您在我的双CPU桌面上描述的问题。我怀疑这个答案是否准确,因为MSDN显示了大量与OP类似的示例。
private void DoGUISwitch() {
// cruisin for a bruisin' through exception city
object1.Visible = true;
object2.Visible = false;
}
private void DoGUISwitch() {
if (object1.InvokeRequired) {
object1.Invoke(new MethodInvoker(() => { DoGUISwitch(); }));
} else {
object1.Visible = true;
object2.Visible = false;
}
}
public static void InvokeIfRequired(this Control c, Action<Control> action)
{
if(c.InvokeRequired)
{
c.Invoke(new Action(() => action(c)));
}
else
{
action(c);
}
}
object1.InvokeIfRequired(c => { c.Visible = true; });
public static void InvokeIfRequired<T>(this T c, Action<T> action)
where T : Control
private void DoGUISwitch()
{
Invoke( ( MethodInvoker ) delegate {
object1.Visible = true;
object2.Visible = false;
});
}
<?xml version="1.0" encoding="utf-8" ?>
<CodeSnippet Format="1.0.0" xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
<Header>
<Title>ThreadsafeInvoke</Title>
<Shortcut></Shortcut>
<Description>Wraps code in an anonymous method passed to Invoke for Thread safety.</Description>
<SnippetTypes>
<SnippetType>SurroundsWith</SnippetType>
</SnippetTypes>
</Header>
<Snippet>
<Code Language="CSharp">
<![CDATA[
Invoke( (MethodInvoker) delegate
{
$selected$
});
]]>
</Code>
</Snippet>
</CodeSnippet>
public static void InvokeIfRequired(this Control control, MethodInvoker action)
{
// See Update 2 for edits Mike de Klerk suggests to insert here.
if (control.InvokeRequired) {
control.Invoke(action);
} else {
action();
}
}
richEditControl1.InvokeIfRequired(() =>
{
// Do anything you want with the control here
richEditControl1.RtfText = value;
RtfHelpers.AddMissingStyles(richEditControl1);
});
public static void InvokeIfRequired(this ISynchronizeInvoke obj,
MethodInvoker action)
{
if (obj.InvokeRequired) {
var args = new object[0];
obj.Invoke(action, args);
} else {
action();
}
}
// When the form, thus the control, isn't visible yet, InvokeRequired returns false,
// resulting still in a cross-thread exception.
while (!control.Visible)
{
System.Threading.Thread.Sleep(50);
}
delegate void ShowMessageCallback(string message);
private void Form1_Load(object sender, EventArgs e)
{
ShowMessageCallback showMessageDelegate = new ShowMessageCallback(ShowMessage);
}
private void ShowMessage(string message)
{
if (this.InvokeRequired)
this.Invoke(showMessageDelegate, message);
else
labelMessage.Text = message;
}
void Message_OnMessage(object sender, Utilities.Message.MessageEventArgs e)
{
ShowMessage(e.Message);
}
private void DoGUISwitch() {
if (object1.InvokeRequired) {
object1.Invoke(new MethodInvoker(() => { DoGUISwitch(); }));
} else {
object1.Visible = true;
object2.Visible = false;
}
}
public delegate void InvokeIfRequiredDelegate<T>(T obj)
where T : ISynchronizeInvoke;
public static void InvokeIfRequired<T>(this T obj, InvokeIfRequiredDelegate<T> action)
where T : ISynchronizeInvoke
{
if (obj.InvokeRequired)
{
obj.Invoke(action, new object[] { obj });
}
else
{
action(obj);
}
}
progressBar1.InvokeIfRequired(o =>
{
o.Style = ProgressBarStyle.Marquee;
o.MarqueeAnimationSpeed = 40;
});
private void AddRowToListView(ScannerRow row, bool suspend)
{
if (IsFormClosing)
return;
if (this.InvokeRequired)
{
var A = new Action(() => AddRowToListView(row, suspend));
this.Invoke(A);
return;
}
//as of here the Code is thread-safe
control.InvokeIfRequired(c => c.Visible = false);
return control.InvokeIfRequired(c => {
c.Visible = value
return c.Visible;
});