3

別のスレッドからWebブラウザの情報にアクセスしようとしています。にアクセスしようとするとbrowser.DocumentTitle、次のエラーが発生します。

The name DocumentTitle does not exist in the current context

DoWorkまたはメソッド内のWebページに正常に移動できますが、クラッシュせずProcessWebPageに関数にアクセスできません。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

最初は、フォーム1の代わりにブラウザ呼び出しを使用します。そして、呼び出し後にコードに戻り、バックグラウンドスレッドとして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 に答える