我使用WebBrowser控件导航到WordPress博客的登录页面。 页面加载正常,但每当我尝试从一个线程访问WebBrowser时。我得到一个特定的演员是无效的例外。同样在调试时,一切都冻结了大约5秒钟。调试时,我尝试访问控件。我得到了所有成员变量的错误。
//in constructor of main form
Thread.CurrentThread.ApartmentState = ApartmentState.STA;
this.CheckForIllegalCrossThreadCalls = false;
mainThreadHandle = new Thread(mainThread);
mainThreadHandle.Start();
private void mainThread()
{
wbMain.Navigate("http://example.com/");
//navigating is set to false in the document complete event.
navigating = true;
while (navigating == true)
Thread.Sleep(5000);
try
{
//Where I get the issues
MessageBox.Show(wbMain.DocumentText);
}
catch (Exception e)
{
}
Thread.Sleep(1000);
}
答案 0 :(得分:8)
WebBrowser是一个引擎盖下的COM组件。一个公寓线程,COM负责以线程安全的方式调用其方法。您的Navigate()调用适用于该原因,它实际上是在UI线程上执行的。什么不起作用的是DocumentText属性,它是在.NET包装器中实现的,它们在某种程度上弄错了代码。当CLR中的COM互操作支持注意到MTA中的线程试图访问存在于STA上的组件的属性时,它会发生炸弹。
您对SetApartmentState()的调用不正确。它是在错误的线程上创建的,UI线程已经是STA。也就是它没有炸弹的原因,你不能在它启动后改变一个线程的公寓状态。您必须在您创建的Thread对象上调用它。它仍然无法解决您的问题,两个STA线程不兼容。
解决问题的两种基本方法。第一个是您在单独的STA线程上创建WebBrowser对象。 this answer中的代码向您展示了如何执行此操作。
您创建的浏览器也无法在表单上显示。这是第二种方式,使用Control.Invoke()自行编组调用。这样做是没有意义的,无论如何你的所有代码都在UI线程上执行,你没有得到并发。这里没有免费的午餐。在线程上运行它只会让您头疼。如果您需要时间处理文档文本,请在单独的线程上运行 代码。
答案 1 :(得分:1)
为什么在使用WebBrowser控件时不使用事件模型?