我在Windows窗体中的跨线程调用有什么问题?
我遇到Windows窗体应用程序的问题。
必须从另一个线程显示一个表单。 所以在表单类中,我有以下代码:
private delegate void DisplayDialogCallback(); public void DisplayDialog() { if (this.InvokeRequired) { this.Invoke(new DisplayDialogCallback(DisplayDialog)); } else { this.ShowDialog(); } }
现在,每次运行它时,都会在this.ShowDialog();
行上抛出InvalidOperationException
this.ShowDialog();
:
“跨线程操作无效:控制’SampleForm’从其创建的线程以外的线程访问。”
这段代码出了什么问题? 这不是一种有效的跨线程调用方式吗? ShowDialog()
有什么特别之处吗?
试试这个:
private delegate void DisplayDialogCallback(); public void DisplayDialog() { if (this.InvokeRequired) { this.Invoke(new DisplayDialogCallback(DisplayDialog)); } else { if (this.Handle != (IntPtr)0) // you can also use: this.IsHandleCreated { this.ShowDialog(); if (this.CanFocus) { this.Focus(); } } else { // Handle the error } } }
请注意InvokeRequired
返回
如果控件的句柄是在与调用线程不同的线程上创建的,则为true(表示必须通过调用方法调用控件); 否则,是的。
因此,如果尚未创建控件,则返回值将为false
!
您可能在表单显示之前执行此代码。
因此, InvokeRequired
返回false
。
我相信这里发生的事情是这个代码是在Form
显示之前运行的。
在.Net中创建Form
,它不会立即获得对特定线程的亲和力。 只有在执行某些操作时,如显示它或抓住手柄才能获得亲和力。 在此之前, InvokeRequired
很难正常运行。
在这种特殊情况下,没有建立关联,也没有父控件,因此InvokeRequired
返回false,因为它无法确定原始线程。
解决此问题的方法是在UI线程上创建控件时建立与控件的关联。 执行此操作的最佳方法是向控件询问其handle属性。
var notUsed = control.Handle;
您可能在显示表单之前获取此代码,因此尚未创建窗口句柄。
您可以在代码之前添加此代码,所有代码都应该是好的:
if (! this.IsHandleCreated) this.CreateHandle();
编辑:您的代码还有另一个问题。 显示表单后,您无法再次调用ShowDialog()。 您将收到无效的操作exception。 您可能希望像其他人提议的那样修改此方法。
您最好直接从调用类调用ShowDialog(),并为BringToFront()或类似的东西提供另一种方法…
您总是可以尝试针对不同的控件进行测试。
例如,您可以访问Application.Forms集合
public Control GetControlToInvokeAgainst() { if(Application.Forms.Count > 0) { return Application.Forms[0]; } return null; }
然后在您的DisplayDialog()方法中,在尝试执行invokerequired调用之前调用GetControlToInvokeAgainst()并测试null。
很可能尚未创建控件的句柄,在这种情况下, Control.InvokeRequired
返回false
。
检查Control.IsHandleCreated
属性以查看是否是这种情况。
我也认为SLaks是正确的。 来自msdn( https://msdn.microsoft.com/en-us/library/system.windows.forms.control.invokerequired.aspx ):
如果找不到合适的句柄,则InvokeRequired方法返回false。
如果它可能在你的情况下,我会尝试在单个方法中组合创建和显示控件,即:
public DisplayDialog static Show() { var result = new DisplayDialog; //possibly cache instance of the dialog if needed, but this could be tricky result.ShowDialog(); return result; }
你可以从另一个线程调用Show
上述就是C#学习教程:我在Windows窗体中的跨线程调用有什么问题?分享的全部内容,如果对大家有所用处且需要了解更多关于C#学习教程,希望大家多多关注—计算机技术网(www.ctvol.com)!
本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。
ctvol管理联系方式QQ:251552304
本文章地址:https://www.ctvol.com/cdevelopment/1019043.html