2009-05-08 5 views
14

이 질문을 쓰기 시작하기 전에, 나는 iframe이 웹 페이지에있는 경우 각 문서가 완료된 후, DocumentCompleted 이벤트 (다음 한 번 더 해고 것, 문제C#에서 WebBrowser 컨트롤 DocumentCompleted 이벤트를 사용하는 방법?

// 1. navigate to page 
// 2. wait until page is downloaded 
// 3. read and write some data from/to iframe 
// 4. submit (post) form 

다음 해결했다려고). 프로그램이 완료되지 않았고 자연적으로 실패한 DOM 데이터를 읽으려고했을 가능성이 큽니다.

그러나이 질문을 작성 갑자기하면서 괴물 '하면 어떻게'나에게 영감을하고, 내가 해결하기 위해 노력하고 있다는 문제를 fix'ed. Google에서이 작업에 실패 했으므로 여기에 게시하는 것이 좋을 것이라고 생각했습니다.

private int iframe_counter = 1; // needs to be 1, to pass DCF test 
    public bool isLazyMan = default(bool); 

    /// <summary> 
    /// LOCK to stop inspecting DOM before DCF 
    /// </summary> 
    public void waitPolice() { 
     while (isLazyMan) Application.DoEvents(); 
    } 

    private void webBrowser1_Navigating(object sender, WebBrowserNavigatingEventArgs e) { 
     if(!e.TargetFrameName.Equals("")) 
      iframe_counter --; 
     isLazyMan = true; 
    } 

    private void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e) { 
     if (!((WebBrowser)sender).Document.Url.Equals(e.Url)) 
      iframe_counter++; 
     if (((WebBrowser)sender).Document.Window.Frames.Count <= iframe_counter) {//DCF test 
      DocumentCompletedFully((WebBrowser)sender,e); 
      isLazyMan = false; 
     } 
    } 

    private void DocumentCompletedFully(WebBrowser sender, WebBrowserDocumentCompletedEventArgs e){ 
     //code here 
    } 

적어도 내 5m 해킹은 정상적으로 작동하는 것처럼 보입니다.

아마 Google이나 MSDN을 쿼리하는 데 실패하고 있는데 찾을 수 없습니다. "C#에서 Webbrowser 컨트롤 DocumentCompleted 이벤트를 사용하는 방법"

비고 : webcontrol에 대해 많은 것을 배운 후, 나는 FuNKY 물건을 발견했습니다.

문서가 완료되었음을 감지하는 경우에도 대부분의 경우 영원히 머물러 있지 않습니다. 페이지 업데이트는 프레임 새로 고침, 요청과 같은 Ajax 또는 서버 측 푸시 (비동기 통신을 지원하는 일부 컨트롤이 필요하며 html 또는 JavaScript interop이 있음)와 같은 여러 가지 방법으로 수행 할 수 있습니다. 또한 일부 iframe은로드되지 않으므로 영원히 기다릴 필요가 없습니다.

if (e.Url != wb.Url) 
+0

DocumentCompleted 이벤트 중에 IsBusy 속성의 상태는 무엇입니까? – AMissico

+0

IsBusy는 첫 번째 프레임이 준비되는 즉시 false를 반환합니다. – Margus

+1

참고로 코드는 여러 개의 일반 프레임에서 작동하지 않습니다. –

답변

14

AJAX 호출도 알고 싶을 수 있습니다.

private void webBrowser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e) 
{ 
    string url = e.Url.ToString(); 
    if (!(url.StartsWith("http://") || url.StartsWith("https://"))) 
    { 
      // in AJAX 
    } 

    if (e.Url.AbsolutePath != this.webBrowser.Url.AbsolutePath) 
    { 
      // IFRAME 
    } 
    else 
    { 
      // REAL DOCUMENT COMPLETE 
    } 
} 
+2

+1하지만 else 부분에는 REAL DOCUMENT COMPLETE이 포함됩니다. if 조건은 iframe이 IFRAME – pug

+0

@pug가 될 것입니다.이를 나타 내기 위해 게시물을 편집했습니다. – AaronLS

0

나는 비슷한 일을했다 :

내가 사용하여 끝났다. 내가하는 일은 ShDocVw를 직접 사용하는 것입니다 (프로젝트에 필요한 모든 interop 어셈블리에 대한 참조 추가). 그런 다음 양식에 WebBrowser 컨트롤을 추가하지 않지만 AXShDocVw.AxWebBrowser 컨트롤을 추가합니다.

탐색하고 나는 다음과 같은 방법을 사용 기다립니다 :

private void GotoUrlAndWait(AxWebBrowser wb, string url) 
{ 
    object dummy = null; 
    wb.Navigate(url, ref dummy, ref dummy, ref dummy, ref dummy); 

    // Wait for the control the be initialized and ready. 
    while (wb.ReadyState != SHDocVw.tagREADYSTATE.READYSTATE_COMPLETE) 
     Application.DoEvents(); 
} 
+2

페이지가 "완료"되지 않으므로 페이지가 Ajax를 사용하고 있으면 실패합니다. –

3

나는 온라인이 문제에 대한 작업 해결책을 찾기 위해 아직있다. 다행스럽게도이 방법을 사용하면 문제를 해결하는 데 많은 시간을 할애 할 수 있으며 모든 문제를 해결할 수 있습니다. 필자는 Microsoft가 isBusy 및 document.readystate의 구현/안정성을 변경함에 따라이 문제에 대해 지난 몇 년간 싸웠습니다. IE8에서는 다음 솔루션을 사용해야했습니다. 몇 가지 예외는 있지만 Margus의 질문/답변과 유사합니다. 내 코드는 중첩 프레임, javascript/ajax 요청 및 메타 리디렉션을 처리합니다. 나는 명확성을 위해 코드를 단순화했다. 그러나 5 분 domAccess가 여전히 false 인 경우 웹 페이지를 다시 설정하기 위해 시간 제한 기능 (포함되지 않음)을 사용한다.

private void m_WebBrowser_BeforeNavigate(object pDisp, ref object URL, ref object Flags, ref object TargetFrameName, ref object PostData, ref object Headers, ref bool Cancel) 
{ 
    //Javascript Events Trigger a Before Navigate Twice, but the first event 
    //will contain javascript: in the URL so we can ignore it. 
    if (!URL.ToString().ToUpper().StartsWith("JAVASCRIPT:")) 
    { 
     //indicate the dom is not available 
     this.domAccess = false; 
     this.activeRequests.Add(URL); 
    } 
} 

private void m_WebBrowser_DocumentComplete(object pDisp, ref object URL) 
{ 

    this.activeRequests.RemoveAt(0); 

    //if pDisp Matches the main activex instance then we are done. 
    if (pDisp.Equals((SHDocVw.WebBrowser)m_WebBrowser.ActiveXInstance)) 
    { 
     //Top Window has finished rendering 
     //Since it will always render last, clear the active requests. 
     //This solves Meta Redirects causing out of sync request counts 
     this.activeRequests.Clear(); 
    } 
    else if (m_WebBrowser.Document != null) 
    { 
     //Some iframe completed dom render 
    } 

    //Record the final complete URL for reference 
    if (this.activeRequests.Count == 0) 
    { 
     //Finished downloading page - dom access ready 
     this.domAccess = true; 
    } 
} 
+0

이전 IE 버전과의 차이점을 자세히 설명해 주시겠습니까? – peterchen

+1

초기 웹 브라우저 자동화에서 나는 documentcomplete 함수를 간단하게 사용할 수있었습니다 - 이것은 2002/3 년경이었습니다 - ie5.5/6. pdisp 오브젝트가 맨 위. 서 창과 일치하면. 서가 완전히 준비되었고 항상 해고되었습니다. 요즘 ~ 불이 났을 때 문서가 준비되었음을 확신 할 수 있지만, 비효율적 인 타임 아웃없이 비동기 이벤트 모델에서 이벤트가 발생하지 않을 때 어떻게 알 수 있습니까? IsBusy는 마우스 커서를 변경하기위한 좋은 지표 였지만, 최근 버전 인 7 & 8에서는 IsBusy가 무한히 유지되는 것을 보았습니다. –

+0

그리고 정확하게 AJAX 요청이 IE6까지 이러한 이벤트를 올바르게 트리거하지 않았기 때문에 ie7 또는 ie8은 이벤트를 탐색하기 전에 복제를 트리거합니다. 그리고 네비게이션 수명주기의 완료 상태를 결정하는 데 도움이되지 않기 때문에 전체 이벤트를 완료하거나 다운로드하면 걱정하지 마십시오. –

2

는 토르스텐 달리 내가 SHDOCVW를 사용하지 않았지만, 내가 readyState가 확인 루프를 추가하고 응용 프로그램을 사용하고 있었다의 차이가 무슨 짓을했는지 :

이를 사용하는 것이 좋습니다.준비가되지 않은 동안 DoEvents(). 여기 내 코드입니다 :

 this.webBrowser.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(WebBrowser_DocumentCompleted); 
     foreach (var item in this.urlList) // This is a Dictionary<string, string> 
     { 
      this.webBrowser.Navigate(item.Value); 
      while (this.webBrowser1.ReadyState != WebBrowserReadyState.Complete) 
      { 
       Application.DoEvents(); 
      } 
     } 

그리고/다른 사용자의 의견에 따라 교체하면 내가 마지막으로하지만, WebBrowser_DocumentCompleted의 결과를 확인하기 위해 유키의 솔루션을 사용 :

 private void WebBrowser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e) 
    { 
     string url = e.Url.ToString(); 
     var browser = (WebBrowser)sender; 

     if (!(url.StartsWith("http://") || url.StartsWith("https://")))  
     {    
      // in AJAX  
     } 
     if (e.Url.AbsolutePath != this.webBrowser.Url.AbsolutePath)  
     { 
      // IFRAME   
     }  
     else  
     {    
      // REAL DOCUMENT COMPLETE 
      // Put my code here 
     } 
    } 

이 마법처럼 일했다 :)

-1

FeiBao의 코드와 함께 작동하는 작은 개선점에 대해 한 줄 또는 두 줄을 놓으려고 생각했습니다. 아이디어는 웹 페이지에 획기적인 (자바 스크립트) 변수를 삽입하고 그 변수를 사용하여 후속 DocumentComplete 이벤트 중 어떤 것이 실제 거래인지를 감지하는 것입니다. 나는 그것이 방탄하는 것은 의심 스럽지만, 그것이 부족한 접근보다 일반적으로 더 안정적으로 일 해왔다. 모든 의견 환영. 다음은 상용구 코드입니다.

void WebBrowser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e) 
    { 
     string url = e.Url.ToString(); 
     var browser = (WebBrowser)sender; 

     if (!(url.StartsWith("http://") || url.StartsWith("https://"))) 
     { 
      // in AJAX  
     } 
     if (e.Url.AbsolutePath != this.webBrowser.Url.AbsolutePath) 
     { 
      // IFRAME   
     } 
     else if (browser.Document != null && (bool)browser.Document.InvokeScript("eval", new object[] { @"typeof window.YourLandMarkJavascriptVariableHere === 'undefined'" })) 
     { 
      ((IHTMLWindow2)browser.Document.Window.DomWindow).execScript("var window.YourLandMarkJavascriptVariableHere = true;"); 

      // REAL DOCUMENT COMPLETE 
      // Put my code here 
     } 
    }