3

我正在尝试从另一个线程访问网络浏览器上的信息。尝试访问时browser.DocumentTitle,我收到此错误:

The name DocumentTitle does not exist in the current context

我可以成功导航到DoWorkorProcessWebPage方法中的网页,但我无法在GetTitle不崩溃的情况下访问该功能。几天来,我一直在独自研究这一部分,根本无法弄清楚。

这是问题代码:

浏览器代码

class BrowserInterface : Form
{
    WebBrowser browser;
    Thread thread;

    State state;

    public State State { get { return state; } }

    public BrowserInterface()
    {
        Initialize();
    }

    void Initialize()
    {
        browser = new WebBrowser();
        state = State.Null;
        state = State.Initializing;
        thread = new Thread(StartThread);
        thread.SetApartmentState(ApartmentState.STA);
        thread.Start();

        while (state == State.Initializing) Thread.Sleep(20);
    }

    void StartThread()
    {
        browser = new WebBrowser();
        browser.Dock = DockStyle.Fill;
        browser.Name = "webBrowser";
        browser.ScrollBarsEnabled = false;
        browser.TabIndex = 0;
        browser.DocumentCompleted +=
            new WebBrowserDocumentCompletedEventHandler(this.Web_Completed);
        Form form = new Form();
        form.Controls.Add(browser);
        form.Name = "Browser";
        state = State.Null;
        Application.Run(form);
    }

    public void Navigate(string url)
    {
        state = State.Navigating;
        if (browser.IsDisposed)
            Initialize();
        browser.Navigate(url);
    }

    public string GetTitle()
    {
        if (InvokeRequired)
        {
            BeginInvoke(new MethodInvoker(() => GetTitle()));
        }
        return browser.DocumentTitle;
    }

    private void Web_Completed(object sender, WebBrowserDocumentCompletedEventArgs e)
    {
        var br = sender as WebBrowser;
        if (br.Url == e.Url)
            state = State.Completed;

    }
}

enum State
{
    Initializing,
    Null,
    Navigating,
    Completed
}

其他线程

class Controller
{
    public int ThreadsAllowed;

    private ManualResetEvent[] resetEvent;
    private BrowserInterface[] browser;

    static Thread mainThread;

    bool run;
    bool exit;

    public Controller(int threadsAllowed)
    {
        ThreadsAllowed = threadsAllowed;

        resetEvent = new ManualResetEvent[ThreadsAllowed];
        browser = new BrowserInterface[ThreadsAllowed];

        for (int i = 0; i < ThreadsAllowed; i++)
        {
            resetEvent[i] = new ManualResetEvent(true);
            browser[i] = new BrowserInterface();
        }

        ThreadPool.SetMaxThreads(ThreadsAllowed, ThreadsAllowed);

        mainThread = new Thread(RunThread);
        mainThread.Start();

        run = false;
        exit = false;
    }

    public void Run()
    {
        run = true;
    }

    void RunThread()
    {
        while (true)
        {
            while (!run) Thread.Sleep(20);
            while (mode == ScoutMode.Off) Thread.Sleep(100);

            //wait for the last set to complete
            WaitHandle.WaitAll(resetEvent);
            if (exit)
                break;

             for (int i = 0; i < ThreadsAllowed; i++)
             ThreadPool.QueueUserWorkItem(DoWork, i);             
        }
    }

    void DoWork(object o)
    {
        int i = (int)o;
        if(browser[i].state == State.null)
        {
            …
            … navigation code that works …
            …
            return;
        }
        else if(browser[i].state == State.Completed)    
            ProcessWebPage(i);         

    }

    void ProcessWebPage(int i)
    {
        string title;
        try
        {
            title = browser[i].GetTitle();
        }
        catch { return; }
    }
}
4

2 回答 2

1

伤害我的眼睛是你的GetTitle功能。使用时MethodInvoker,您正在处理void类型的方法,也就是说,您无法从函数中获取返回值。这就是为什么您需要一个可以返回值的委托的原因。

此外,您必须有else声明,因此实际上需要在调用时不要尝试返回值。

class BrowserInterface : Form
{
    /* ... */

    private delegate string StringDelegate();

    public string GetTitle()
    {
        /*
        if (InvokeRequired)
        {
            BeginInvoke(new MethodInvoker(() => GetTitle()));
        }
        return browser.DocumentTitle;
        */

        if (InvokeRequired)
        {
            object result = Invoke(new StringDelegate(GetTitle));
            return (string)result;
        }
        else
            return browser.DocumentTitle;
    }

    /* ... */
}
于 2012-09-02T21:16:54.283 回答
0

首先,使用浏览器调用而不是表单。调用后您将返回代码并尝试访问 browser.DocumentTitle 作为后台线程的主要问题。为避免这种情况,请添加 else 构造。

public string GetTitle()
{
    if (this.browser.InvokeRequired)
    {
        this.browser.Invoke(new MethodInvoker(() => GetTitle()));
    }
    else
    {
        return browser.DocumentTitle;
    }
}
于 2012-09-02T21:15:23.607 回答