سؤال

أنا أستخدم عنصر تحكم .NET WebBrowser.كيف أعرف أن صفحة الويب محملة بالكامل؟

أريد أن أعرف متى لا يقوم المتصفح بجلب المزيد من البيانات.(اللحظة التي يكتب فيها IE كلمة "تم" في شريط الحالة الخاص به...).

ملحوظات:

  • قد تحدث أحداث DocumentComplete/NavigateComplete عدة مرات لموقع ويب يحتوي على إطارات متعددة.
  • حالة جاهزية المتصفح لا تحل المشكلة أيضًا.
  • لقد حاولت التحقق من عدد الإطارات في مجموعة الإطارات ثم أحسب عدد المرات التي أحصل فيها على حدث DocumentComplete ولكن هذا لا يعمل أيضًا.
  • this.WebBrowser.IsBusy لا يعمل أيضًا.يكون دائمًا "خطأ" عند التحقق منه في معالج اكتمال المستند.
هل كانت مفيدة؟

المحلول 4

إليك ما نجح أخيرًا بالنسبة لي:

       public bool WebPageLoaded
    {
        get
        {
            if (this.WebBrowser.ReadyState != System.Windows.Forms.WebBrowserReadyState.Complete)
                return false;

            if (this.HtmlDomDocument == null)
                return false;

            // iterate over all the Html elements. Find all frame elements and check their ready state
            foreach (IHTMLDOMNode node in this.HtmlDomDocument.all)
            {
                IHTMLFrameBase2 frame = node as IHTMLFrameBase2;
                if (frame != null)
                {
                    if (!frame.readyState.Equals("complete", StringComparison.OrdinalIgnoreCase))
                        return false;

                }
            }

            Debug.Print(this.Name + " - I think it's loaded");
            return true;
        }
    }

في كل حدث إكمال مستند، أقوم بتشغيل كل عناصر html وأتحقق من جميع الإطارات المتاحة (أعلم أنه يمكن تحسينها).لكل إطار أتحقق من حالته الجاهزة.إنها موثوقة جدًا ولكن تمامًا كما قال jeffamaphone، فقد رأيت بالفعل مواقع أدت إلى بعض التحديثات الداخلية.لكن الكود أعلاه يلبي احتياجاتي.

يحرر:يمكن أن يحتوي كل إطار على إطارات بداخله، لذا أعتقد أنه يجب تحديث هذا الرمز للتحقق بشكل متكرر من حالة كل إطار.

نصائح أخرى

طريقتي في فعل شيء ما عندما يتم تحميل الصفحة بالكامل (بما في ذلك الإطارات) يشبه هذا:

using System.Windows.Forms;
    protected delegate void Procedure();
    private void executeAfterLoadingComplete(Procedure doNext) {
        WebBrowserDocumentCompletedEventHandler handler = null;
        handler = delegate(object o, WebBrowserDocumentCompletedEventArgs e)
        {
            ie.DocumentCompleted -= handler;
            Timer timer = new Timer();
            EventHandler checker = delegate(object o1, EventArgs e1)
            {
                if (WebBrowserReadyState.Complete == ie.ReadyState)
                {
                    timer.Dispose();
                    doNext();
                }
            };
            timer.Tick += checker;
            timer.Interval = 200;
            timer.Start();
        };
        ie.DocumentCompleted += handler;
    }

من أساليبي الأخرى تعلمت بعض "لا تفعل":

  • لا تحاول ثني الملعقة..؛-)
  • لا تحاول إنشاء إنشاء متقن باستخدام أحداث DocumentComplete وFrames وHtmlWindow.Load.سيكون الحل الخاص بك هشًا إذا كان يعمل على الإطلاق.
  • لا تستخدم System.Timers.Timer بدلاً من Windows.Forms.Timer, ، ستبدأ الأخطاء الغريبة في الحدوث في أماكن غريبة إذا قمت بذلك، وذلك بسبب تشغيل المؤقت على مؤشر ترابط مختلف عن بقية تطبيقك.
  • لا تستخدم فقط Timer بدون DocumentComplete لأنه قد يتم تشغيله قبل أن يبدأ تحميل صفحتك وسينفذ التعليمات البرمجية الخاصة بك قبل الأوان.

إليك كيفية حل المشكلة في طلبي:

private void wbPost_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
    if (e.Url != wbPost.Url)
        return;
    /* Document now loaded */
}

ها هي نسختي التي تم اختبارها.فقط اجعل هذا لك DocumentCompleted Event Handler ووضع الرمز الذي تريد الاتصال به فقط مرة واحدة في الطريقة OnWebpageReallyLoaded().على نحو فعال، يحدد هذا الأسلوب متى كانت الصفحة مستقرة لمدة 200 مللي ثانية ثم يقوم بعمله.

// event handler for when a document (or frame) has completed its download
Timer m_pageHasntChangedTimer = null;
private void webBrowser_DocumentCompleted( object sender, WebBrowserDocumentCompletedEventArgs e ) {
    // dynamic pages will often be loaded in parts e.g. multiple frames
    // need to check the page has remained static for a while before safely saying it is 'loaded'
    // use a timer to do this

    // destroy the old timer if it exists
    if ( m_pageHasntChangedTimer != null ) {
        m_pageHasntChangedTimer.Dispose();
    }

    // create a new timer which calls the 'OnWebpageReallyLoaded' method after 200ms
    // if additional frame or content is downloads in the meantime, this timer will be destroyed
    // and the process repeated
    m_pageHasntChangedTimer = new Timer();
    EventHandler checker = delegate( object o1, EventArgs e1 ) {
        // only if the page has been stable for 200ms already
        // check the official browser state flag, (euphemistically called) 'Ready'
        // and call our 'OnWebpageReallyLoaded' method
        if ( WebBrowserReadyState.Complete == webBrowser.ReadyState ) {
            m_pageHasntChangedTimer.Dispose();
            OnWebpageReallyLoaded();
        }
    };
    m_pageHasntChangedTimer.Tick += checker;
    m_pageHasntChangedTimer.Interval = 200;
    m_pageHasntChangedTimer.Start();
}

OnWebpageReallyLoaded() {
    /* place your harvester code here */
}

ماذا عن استخدام جافا سكريبت في كل إطار لتعيين علامة عند اكتمال الإطار، ثم اطلب من C# إلقاء نظرة على العلامات؟

ليس لدي بديل لك، ولكني أتساءل عما إذا كان IsBusy كائن الملكية true أثناء معالج إكمال المستند لأن المعالج لا يزال قيد التشغيل وبالتالي WebBrowser التحكم لا يزال من الناحية الفنية "مشغولاً".

سيكون الحل الأبسط هو الحصول على حلقة يتم تنفيذها كل 100 مللي ثانية أو نحو ذلك حتى يتم تنفيذ الأمر IsBusy تتم إعادة تعيين العلامة (مع الحد الأقصى لوقت التنفيذ في حالة حدوث أخطاء).وهذا بالطبع يفترض ذلك IsBusy لن يتم تعيين ل false في أي وقت أثناء تحميل الصفحة.

إذا تم تنفيذ معالج اكتمال المستند على مؤشر ترابط آخر، فيمكنك استخدام قفل لإرسال مؤشر الترابط الرئيسي الخاص بك إلى وضع السكون وتنشيطه من مؤشر ترابط اكتمال المستند.ثم تحقق من IsBusy العلم، وإعادة قفل الموضوع الرئيسي لا يزال قائما true.

لست متأكدًا من أنه سيعمل ولكن حاول إضافة حدث JavaScript "onload" على مجموعة الإطارات الخاصة بك مثل هذا:

function everythingIsLoaded() { alert("everything is loaded"); }
var frameset = document.getElementById("idOfYourFrameset");
if (frameset.addEventListener)
    frameset.addEventListener('load',everythingIsLoaded,false); 
else
    frameset.attachEvent('onload',everythingIsLoaded); 

هل يمكنك استخدام مسج؟ثم يمكنك بسهولة ربط الأحداث الجاهزة للإطار على الإطارات المستهدفة.يرى هذا الإجابة عن الاتجاهات.هذا مشاركة مدونة لديها أيضا مناقشة حول هذا الموضوع.وأخيرا هناك أ توصيل في التي يمكنك استخدامها.

الفكرة هي أن تحسب عدد الإطارات في صفحة الويب باستخدام:

$("iframe").size()

ثم تقوم بحساب عدد المرات التي تم فيها إطلاق حدث iframe الجاهز.

سوف تحصل على حدث BeforeNavigate وDocumentComplete لصفحة الويب الخارجية، بالإضافة إلى كل إطار.ستعلم أنك انتهيت عندما تحصل على حدث DocumentComplete لصفحة الويب الخارجية.يجب أن تكون قادرًا على استخدام المعادل المُدار لـ IWebBrowser2::TopLevelContainer() لتحديد هذا.

ومع ذلك، احذر، يمكن لموقع الويب نفسه تشغيل المزيد من التنقلات بين الإطارات في أي وقت يريده، لذلك لا تعرف أبدًا ما إذا كانت الصفحة قد تمت بالفعل إلى الأبد.أفضل ما يمكنك فعله هو الاحتفاظ بعدد جميع عمليات BeforeNavigates التي تراها وتقليل العدد عندما تحصل على DocumentComplete.

يحرر:إليك المستندات المُدارة: TopLevelContainer.

أنا فقط أستخدم طريقة webBrowser.StatusText.عندما تقول "تم" يتم تحميل كل شيء!أم هل فاتني شيء؟

يجب أن يعمل التحقق من IE.readyState = READYSTATE_COMPLETE، ولكن إذا لم يكن ذلك موثوقًا بالنسبة لك وتريد حرفيًا معرفة "اللحظة التي يكتب فيها IE "تم" في شريط الحالة الخاص به"، فيمكنك إجراء حلقة حتى يحتوي IE.StatusText على "منتهي".

هل جربت WebBrowser.IsBusy ملكية؟

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top