加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

c# – EventHandle.WaitOne WebBrowser =等待DocumentComplete时

发布时间:2020-12-15 05:41:16 所属栏目:百科 来源:网络整理
导读:我在C#-Program中遇到了WebBrowsing自动化的问题. 我之前使用过代码来获取BHO,并且它正在运行. 但在纯粹的c#程序中,似乎存在某种僵局.我已经指示我的程序点击搜索按钮,然后等待(通过手动重新发送)文档完成信号.但是现在似乎在ManualResetEvent发出超时信号之
我在C#-Program中遇到了WebBrowsing自动化的问题.
我之前使用过代码来获取BHO,并且它正在运行.
但在纯粹的c#程序中,似乎存在某种僵局.我已经指示我的程序点击搜索按钮,然后等待(通过手动重新发送)文档完成信号.但是现在似乎在ManualResetEvent发出超时信号之前不会处理点击搜索按钮.然后单击,并且还会触发DocumentComplete-Event.

对于该程序的结构:
WebBrowser-Control是WindowsForm的一部分. WebBrowser控件传递给运行Thread的Class.该类再次将控件传递给另一个类,其中根据加载的webbrowser编程具体行为.

所以在Code中这样看起来:

>线程的设置

_runner = new Thread(runner);
_runner.SetApartmentState(ApartmentState.STA);
_runner.IsBackground = true;
_runner.Start();

>使用跑步者方法的处理

b.placeTipp(workStructure);

> PlaceTipp方法

public void placeTipp(ref OverallTippStructure tipp)
    {
        _expectedUrl = String.Empty;
        _betUrl = String.Empty;
        _status = BookieStatusType.CHECKLOGIN;

        while (true)
        {
            _mreWaitForAction.Reset();
            checkIETab();

            switch (_status)
            {
                case BookieStatusType.REQUESTWEBSITE:
                    ConsoleWriter.writeToConsole(String.Format("Bookie {0}: Keine IE-Tab vorhanden. Fordere eine an",this.BookieName));
                    //if (RequestIETabEvent != null)
                    //    RequestIETabEvent(this,new EventArgs());
                    _status = BookieStatusType.NAVIGATETOWEBSITE;
                    _mreWaitForAction.Set();
                    break;
                case BookieStatusType.NAVIGATETOWEBSITE:                                                
                    _webBrowser.Navigate(@"http://www.nordicbet.com");
                    break;
                case BookieStatusType.CHECKLOGIN:
                    checkLogin();
                    break;
                case BookieStatusType.LOGINNEEDED:
                    doLogin();
                    break;
                case BookieStatusType.LOGGEDIN:
                    _status = BookieStatusType.SEARCHTIPP;
                    _mreWaitForAction.Set();
                    break;
                case BookieStatusType.SEARCHTIPP:
                    searchTipp(tipp);
                    break;
                case BookieStatusType.NAVTOSB:
                    NavToSB();
                    break;
                case BookieStatusType.GETMARKET:
                    getMarket(tipp);
                    break;
                case BookieStatusType.PLACEBET:
                    placeBet(tipp);
                    break;
                case BookieStatusType.CONFIRMBET:
                    confirmBet();
                    break;
                case BookieStatusType.EXTRACTBETDATA:
                    extractBetId(ref tipp);
                    break;
                case BookieStatusType.FINISHED:
                    return;
            }


            if (!_mreWaitForAction.WaitOne(60000))
            {
                //Sonderüberpüfung be LoginNeeded
                if (_status == BookieStatusType.LOGINNEEDED)
                {
                    //checkLogin();
                    throw new BookieLoginFailedExcpetion();
                }
                //TIMEOUT!
                ConsoleWriter.writeToConsole(String.Format("Bookie {0}: Timeout bei warten auf n?chsten Schritt. Status war {1}",this.BookieName,this._status.ToString()));
                throw new BookieTimeoutExcpetion(String.Format("Bookie {0}: Timeout bei dem Warten auf Ereignis",this.BookieName));
            }
        }
    }

>发生死锁的SearchTipp-Method:

private void searchTipp(OverallTippStructure tipp)
    {
        if (_webBrowser.InvokeRequired)
        {
            _webBrowser.Invoke(new delegatePlaceBet(searchTipp),new object[] { tipp });
        }
        else
        {
            ConsoleWriter.writeToConsole(String.Format("Bookie {0}: Suche Tipp {1}",tipp.BookieMatchName));
            _expectedUrl = String.Empty;
            if (!_webBrowser.Url.ToString().StartsWith("https://www.nordicbet.com/eng/sportsbook"))
            {
                ConsoleWriter.writeToConsole(String.Format("Bookie {0}: Nicht auf Sportsbookseite. Navigiere",this.BookieName));
                _status = BookieStatusType.NAVTOSB;
                _mreWaitForAction.Set();
                return;
            }
            _searchCompleted = false;
            HtmlDocument doc = _webBrowser.Document;

            if (doc != null)
            {

                mshtml.IHTMLInputElement elemSearch = (mshtml.IHTMLInputElement)doc.GetElementById("query").DomElement;
                if (elemSearch != null)
                {
                    Thread.Sleep(Delayer.delay(2000,10000));
                    elemSearch.value = tipp.BookieMatchName;

                    mshtml.IHTMLElement elemSearchButton = (mshtml.IHTMLElement)doc.GetElementById("search_button").DomElement;
                    if (elemSearchButton != null)
                    {
                        Thread.Sleep(Delayer.delay(900,4000));

                        elemSearchButton.click();
                        //elemSearchButton.InvokeMember("click");

                        if (!_mreWaitForAction.WaitOne(10000)) //Here The Deadlock happens
                        {
                            //Now the click event and therefor the search will be executed
                            ConsoleWriter.writeToConsole(String.Format("Bookie {0}: Suche ist auf Timeout gelaufen",this.BookieName));
                            throw new BookieTimeoutExcpetion(String.Format("Bookie {0}: Suche ist auf Timeout gelaufen",this.BookieName));
                        }                                                        

                        _mreWaitForAction.Reset();
                        HtmlElement spanResult = doc.GetElementById("total_ocs_count");
                        while (spanResult == null)
                        {
                            Thread.Sleep(500);
                            spanResult = doc.GetElementById("total_ocs_count");
                        }

                        int total_ocs_count = 0;
                        if (!Int32.TryParse(spanResult.InnerHtml,out total_ocs_count))
                        {
                            ConsoleWriter.writeToConsole(String.Format("Bookie {0}: Tip {1} nicht gefunden",tipp.BookieMatchName));
                            throw new BookieTippNotFoundExcpetion(String.Format("Bookie {0}: Tip {1} nicht gefunden",tipp.BookieMatchName));
                        }

                        if (total_ocs_count <= 0)
                        {
                            ConsoleWriter.writeToConsole(String.Format("Bookie {0}: Tip {1} nicht gefunden",tipp.BookieMatchName));
                        }
                        /*
                    else if (total_ocs_count > 1)
                    {
                        throw new BookieMoreThanOneFoundExcpetion(String.Format("Bookie {0}: Tipp {1} nicht eindeutig",tipp.BookieMatchName));
                    }
                    */
                        ConsoleWriter.writeToConsole(String.Format("Bookie {0}: Tip {1} gefunden",tipp.BookieMatchName));
                        _status = BookieStatusType.GETMARKET;
                    }
                }
            }
            _mreWaitForAction.Set();
        }
    }

有人知道这里发生了什么?

谢谢

lichtbringer

解决方法

通过执行_webBrowser.Invoke(new delegatePlaceBet(searchTipp),new object [] {tipp}),可以在主UI线程上同步执行searchTipp方法.这是可以理解的,因为您无法从创建控件的原始线程以外的任何线程访问WebBrowser API.

但是,通过这样做,_mreWaitForAction.WaitOne(10000)调用将在主UI线程上执行,从而有效地阻止消息循环(由Application.Run启动). WebBrowser需要一个功能性的消息循环,它不断地传递Windows消息,否则DocumentCompleted不会被触发,并且您将陷入僵局.

我的理解是,您只需在此处创建另一个线程来组织自动化方案的工作流程.你真的不需要另一个线程. Here’s an example如何在主UI线程上异步完成,使用async / await和here’s an example在控制台应用程序中使用WebBrowser.

或者,作为一种变通方法,您可以使用here中的WaitWithDoEvents,如下所示:_mreWaitForAction.WaitWithDoEvents(10000).它在等待处理消息时等待处理.您应该了解使用Application.DoEvents()创建嵌套消息循环的potential implications.

注意,如果使用嵌套消息循环,则仍然不需要单独的线程.它将为您提供主UI线程上的线性代码工作流程.例:

private void buttonStart_Click(object sender,EventArgs e)
{
    using (var mre = new ManualResetEvent(false))
    {
        WebBrowserDocumentCompletedEventHandler handler = (s,args) => 
            mre.Set();
        this.webBrowser.DocumentCompleted += handler;
        try
        {
            this.webBrowser.Navigate("http://www.example.com");
            mre.WaitWithDoEvents(10000);
        }
        finally
        {
            this.webBrowser.DocumentCompleted -= handler;
        }
    }
    MessageBox.Show(this.webBrowser.Document.Body.OuterHtml);
}

虽然正如我上面提到的,你可以更自然地实现同样的目的,没有嵌套的消息循环,使用async / await,这是这??样做的首选方法,IMO.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读