我遇到了Windows窗体应用程序的问题。
表单必须显示在另一个帖子中。所以在表单类中,我有以下代码:
private delegate void DisplayDialogCallback();
public void DisplayDialog()
{
if (this.InvokeRequired)
{
this.Invoke(new DisplayDialogCallback(DisplayDialog));
}
else
{
this.ShowDialog();
}
}
现在,每次运行时,行InvalidOperationException
都会this.ShowDialog();
投放{/ 1}}:
“跨线程操作无效:控制'SampleForm'从其创建的线程以外的线程访问。”
这段代码有什么问题?这不是一种进行跨线程调用的有效方法吗? ShowDialog()
是否有特别之处?
答案 0 :(得分:8)
您可能在表单显示之前执行此代码
因此,InvokeRequired
正在返回false
。
答案 1 :(得分:5)
我相信这里发生的事情是这个代码在Form
显示之前运行。
在.Net中创建Form
时,它不会立即获得特定线程的亲和力。只有在执行某些操作时,如显示它或抓住手柄才能获得亲和力。在此之前,InvokeRequired
很难正常运行。
在这种特殊情况下,没有建立关联,也不存在父控件,因此InvokeRequired
返回false,因为它无法确定原始线程。
解决此问题的方法是在UI线程上创建控件时为其建立关联。执行此操作的最佳方法是向控件询问其句柄属性。
var notUsed = control.Handle;
答案 2 :(得分:4)
试试这个:
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
返回
如果控件的Handle是,则为true 在与...不同的线程上创建 调用线程(表示你 必须通过调用控件 一个调用方法);否则,错误。
因此,如果尚未创建控件,则返回值为false
!
答案 3 :(得分:1)
您可能会在显示表单之前获取此代码,因此尚未创建窗口句柄。
您可以在代码之前添加此代码,所有代码都应该是好的:
if (! this.IsHandleCreated)
this.CreateHandle();
编辑:您的代码还有另一个问题。显示表单后,您无法再次调用ShowDialog()。您将收到无效的操作异常。您可能希望像其他人提议的那样修改此方法。
你最好直接从调用类调用ShowDialog(),并为BringToFront()或类似的东西提供另一种方法......
答案 4 :(得分:0)
您可以尝试针对不同的控件进行测试。
例如,您可以访问Application.Forms集合
public Control GetControlToInvokeAgainst()
{
if(Application.Forms.Count > 0)
{
return Application.Forms[0];
}
return null;
}
然后在您的DisplayDialog()方法中,在尝试执行invokerequired调用之前,调用GetControlToInvokeAgainst()并测试null。
答案 5 :(得分:0)
很可能尚未创建控件的句柄,在这种情况下Control.InvokeRequired
会返回false
。
检查Control.IsHandleCreated
属性以查看是否属于这种情况。
答案 6 :(得分:0)
我也认为SLaks是正确的。来自msdn(http://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