2

我想从不同的线程访问静态 WebBrowser。

这是我的示例代码:

public partial class MainFrame : Form
{
    public static WebBrowser webBrowser = new WebBrowser();

     public MainFrame()
     {
         InitializeComponent();
     }
}

class Job
{
    public void Process()
    {
        MainFrame.webBrowser.Navigate("http://www.google.com");
        while (MainFrame.webBrowser.ReadyState != WebBrowserReadyState.Complete)
        {
            Thread.Sleep(1000);
            Application.DoEvents();
        }
    }
}

为简单起见,假设我有 2 个线程。线程 1 调用 Process() 函数并等待它完成,所以在这个阶段 webBrowser 应该处于 CompleteWebBrowserReadyState模式。

线程 1 完成 10 秒后,线程 2 调用Process()函数。此时如果我调试我的代码并在Process()函数的第一行放置一个 BreakPoint 并观察MainFrame.webBrowser变量,我会看到:

MainFrame.webBrowser 的调试信息

换句话说,它以某种方式无法访问。有人知道这个问题的任何解决方案吗?

附加信息:线程 1 完成后 10 秒,如果我再次调用线程 1,那么一切看起来都很好。

4

1 回答 1

2

您不能从未在其上创建控件的线程直接调用 WebBrowser 控件的方法或属性。您需要将此类调用代理到控件的父线程中。一种方法是使用BeginInvoke,但它是异步的。

如果你真的需要同步,你可以使用SynchronizationContext.Send,像这样:

public partial class MainFrame : Form
{
    public static WebBrowser webBrowser = new WebBrowser();

    public static System.Threading.SynchronizationContext mainThreadContext = System.Threading.SynchronizationContext.Current;


    public MainFrame()
    {
        InitializeComponent();
    }
}

class Job
{
    public void Process()
    {
        mainThreadContext.Send(delegate 
        {
            MainFrame.webBrowser.Navigate("http://www.google.com");
        }, null);

        bool ready = false;
        while (!ready)
        {
            mainThreadContext.Send(delegate 
            {
                ready = MainFrame.webBrowser.ReadyState != WebBrowserReadyState.Complete;
            }, null);
            Thread.Sleep(1000);
            // if you don't have any UI on this thread, DoEvent is redundant
            Application.DoEvents(); 
        }
    }
}

无论如何,上面的代码在我看来并不是一个好的设计。你想达到什么目的?可能有更好的方法来做到这一点。也许,您可以只使用WebBrowser.DocumentCompleted事件?

于 2013-08-11T00:50:19.320 回答