1

私が構築しているこの関数の流れを理解するのに苦労しています。

    public void PortalLogin(AutoResetEvent signal)
            {
                // Navigate to portal
                string portalUrl = "website_name";
                string portalEmail = "email@email.com";
                string portalPassword = "password";
                Action action2 = () =>
                {
                    webBrowser2.Tag = signal;
                    webBrowser2.Navigate(portalUrl);
                    webBrowser2.DocumentCompleted -= WebBrowserDocumentCompleted;
                    webBrowser2.DocumentCompleted += WebBrowserDocumentCompleted;
                };
                webBrowser2.Invoke(action2);
                signal.WaitOne();

                // Login to O365 portal
                webBrowser2.Invoke(new Action(() =>
                {
                    HtmlElement head = webBrowser2.Document.GetElementsByTagName("head")[0];
                    HtmlElement testScript = webBrowser2.Document.CreateElement("script");
                    IHTMLScriptElement element = (IHTMLScriptElement)testScript.DomElement;
                    element.text = "function PortalLogin() { document.getElementById('userid').value = '" + portalEmail + "'; document.getElementById('password').value = '" + portalPassword + "';  document.getElementById('login').submit(); }";
                    head.AppendChild(testScript);
                    webBrowser2.Document.InvokeScript("PortalLogin");
                }));
            }

... more functions after this

document.getElementById('login').submit();ステップスルーすると、スクリプトの一部を「時間通りに」呼び出していないようです。InvokeScript完全に完了するまで何も起こらないようにするにはどうすればよいですか?

また、余分なコードやクリーンアップできるものがある場合は、それも素晴らしいことです。

EDIT : ここに DocumentCompleted 関数があります。

private void WebBrowserDocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs Url)
        {
            ((AutoResetEvent)((WebBrowser)sender).Tag).Set();
        }
4

1 に答える 1

4

いくつかのポイント:

DocumentCompleted一度イベント ハンドラーを外部に追加PortalLoginして、同じハンドラーを再利用できます。AutoResetEventの後に自動的に非シグナル状態にリセットするを使用してsignal.WaitOne()いるため、 の永続的なハンドラーが 1 つだけで問題ありませんDocumentCompleted

メソッドが利用可能document.getElementById('login')な有効な要素を返しますか? submitに電話する前に確認してInvokeScriptください。ログインは 2 つの手順で行うことができます。たとえば、次のようになります。

            element.text = "function PortalLogin() { document.getElementById('userid').value = '" + portalEmail + "'; document.getElementById('password').value = '" + portalPassword + "';  }" +
                "function ExecuteLogin() { document.getElementById('login').submit(); }";
            head.AppendChild(testScript);
            webBrowser2.Document.InvokeScript("PortalLogin");
            // verify document.getElementById('login') here
            webBrowser2.Document.InvokeScript("ExecuteLogin");

注: 成功した場合、送信は最終的に別のDocumentCompletedイベントをトリガーします。

シングル スレッドとawait/async patternを使用して、このコードをリファクタリングします。DocumentCompletedを使用してタスクとしてラップできますTaskCompletionSource(方法は次のとおりです)。

以下は、 を使用した場合の様子async/awaitです。MessageBox.ShowDOM操作を行うことができる場所。すべてがメインの UI スレッドで行われることに注意してください (もちろん非同期で)。私にはかなり簡単に見えます。

void Form1_Load(object sender, EventArgs e)
{
    var task = DoNavigationAsync();
    task.ContinueWith((t) =>
    {
        MessageBox.Show("Navigation done!");
    }, TaskScheduler.FromCurrentSynchronizationContext());
}

struct Void {}; // use an empty struct as parameter to generic TaskCompletionSource

async Task DoNavigationAsync()
{
    Void v;
    TaskCompletionSource<Void> tcs = null; 
    WebBrowserDocumentCompletedEventHandler documentComplete = null;

    documentComplete = new WebBrowserDocumentCompletedEventHandler((s, e) =>
    {
        // more of DocumentCompleted can possibly be fired due to dynamic navigation inside the web page, we don't want them!
        this.WB.DocumentCompleted -= documentComplete;              
        tcs.SetResult(v); // continue from where awaited
    });

    // navigate to www.bing.com
    tcs = new TaskCompletionSource<Void>();
    this.WB.DocumentCompleted += documentComplete;
    this.WB.Navigate("http://www.bing.com");
    await tcs.Task;
    // do whatever you want with this instance of WB.Document
    MessageBox.Show(this.WB.Document.Url.ToString());

    // navigate to www.google.com
    tcs = new TaskCompletionSource<Void>();
    this.WB.DocumentCompleted += documentComplete;
    this.WB.Navigate("http://www.google.com");
    await tcs.Task;
    // do whatever you want with this instance of WB.Document
    MessageBox.Show(this.WB.Document.Url.ToString());

    // navigate to www.yahoo.com
    tcs = new TaskCompletionSource<Void>();
    this.WB.DocumentCompleted += documentComplete;
    this.WB.Navigate("http://www.yahoo.com");
    await tcs.Task;
    // do whatever you want with this instance of WB.Document
    MessageBox.Show(this.WB.Document.Url.ToString());

    return;
}
于 2013-08-16T23:23:24.730 に答える