1

I have a webbrowser which is loading a website. If the website firing the "completed" event, my HTMLElementCollection shows me a count of "179". If I click on the button and call the same method to get all HTMLElements, it tells me a count of "194". The problem is: if the "completed"-Event is firing, some HTMLElements are not loaded, and needs a longer time, and my HTMLElement which I need to click on it, is missing too.

To explain with code:

private void Webbrowser_DocumentComplete(object pDisp, ref object URL)
        {
                if (URL.ToString() == "testsite")
                {
                    HtmlElementCollection c1 = webBrowser1.Document.GetElementsByTagName("div");
                    foreach (HtmlElement e2 in c1)
                    {
                        if (e2.GetAttribute("classname") == "btn3")
                        {
                            if (e2.InnerText == "follow")
                            {
                                e2.InvokeMember("click");
                            }
                        }
                    }
                }
        }

The count of "c1" is 179.

If I wait 1-2 seconds and click then on a button with the same code like:

private void Button1_Click(object sender, EventArgs e)
        {
HtmlElementCollection c1 = webBrowser1.Document.GetElementsByTagName("div");
                    foreach (HtmlElement e2 in c1)
                    {
                        if (e2.GetAttribute("classname") == "btn3")
                        {
                            if (e2.InnerText == "follow")
                            {
                                e2.InvokeMember("click");
                            }
                        }
                    }
        }

The count of "c1" is 194.

The question is: how can I wait some seconds if the page is build completed? I need the count of 194 because there is ONE HTMLElement which I want to click on it!

MGMelli
  • 11
  • 5
  • See the notes here: [How to get an HtmlElement value inside Frames/IFrames?](https://stackoverflow.com/a/53218064/7444103). – Jimi May 01 '19 at 16:52
  • @Jimi why this should help me? – MGMelli May 01 '19 at 16:58
  • You didn't read those notes. Specifically, coupling the `DocumentCompleted` event and `WebBrowser.ReadyState`. Anything else related to the internal documents of a HTML page, which can contain more than one Document. For each document in a HTML page, a `DocumentCompleted` event is raised. The different documents are loaded asynchronously. – Jimi May 01 '19 at 17:01
  • But I only want to achieve that I can wait for example 5 seconds, the page is loading because the controls need the time, and after the 5 seconds I try to click, like while (DateTime.Now < dueTime) { Application.DoEvents(); } -> but the webbrowser stop loading – MGMelli May 01 '19 at 17:07
  • You need to wait until the HtmlElement you're looking for is loaded and rendered. There's not specific *timeout* to wait for. When it's ready, it's ready and you'll get it. Read carefully what I linked and see the related code. Which, btw, is doing exactly what you need to do. – Jimi May 01 '19 at 17:09
  • @Jimi This doesn't helps me, because I only have 4 Frames and that's not what I want.. – MGMelli May 01 '19 at 17:48
  • This would help you exactly because you have more that 1 frame (so, more than one document). You didn't read what's written in the notes I linked. – Jimi May 01 '19 at 19:42
  • @Jimi No it doesn't work. All frames that exists only contains the Google Translator toolbar, that means, that I only find options like "Select this language:" and then 300 counts only with different languages. I used: var test = Frame.Document.All; – MGMelli May 02 '19 at 16:34

2 Answers2

0

You can handle this by using a Timer. The following function is done to wait for some seconds.

    public void WaitForSecond(int min)
    {
        System.Windows.Forms.Timer timer1 = new System.Windows.Forms.Timer();
        if (min == 0 || min < 0) return;
        timer1.Interval = min * 1000;
        timer1.Enabled = true;
        timer1.Start();
        timer1.Tick += (s, e) =>
        {
            timer1.Enabled = false;
            timer1.Stop();

        };
        while (timer1.Enabled)
        {
            Application.DoEvents();
        }
    }

Also, you can reduce your code by LINQ

HtmlElement e2= (from HtmlElement element in 
                  webBrowser1.Document.GetElementsByTagName("div") 
                  select element)
                  .Where(x => x.GetAttribute("classname") != null 
                           && x.GetAttribute("classname") =="btn3"
                           && x.InnerText != null 
                           && x.InnerText == "follow").FirstOrDefault();

First, check your HTML element is loaded or not otherwise wait. If the HTML element is loaded then process the further steps

HtmlElement e2= null;
int cnt = 0;
            do
            {
                WaitForSecond(1);
                cnt++;

                if (cnt > 60)
                {
                   MessageBox.Show("Web page not loaded");
                    break;
                }
                e2= (from HtmlElement element in webBrowser1.Document.GetElementsByTagName("div") select element)
                .Where(x => x.GetAttribute("classname") != null 
                       && x.GetAttribute("classname") =="btn3"
                       && x.InnerText != null 
                       && x.InnerText == "follow").FirstOrDefault();    
            } while e2 == null);
Golda
  • 3,823
  • 10
  • 34
  • 67
  • There is a little problem. The website isn't loading during this action. It is freezed, and that's the reason why I can't find this element. – MGMelli May 02 '19 at 16:18
  • Then you can increase the waiting time using WaitForSecond function. So that it will wait till your website page load. Is it possible to give the web page link? – Golda May 03 '19 at 05:56
  • yes it is possible, and I found a solution (see my answer below) – MGMelli May 03 '19 at 06:52
0

Thank you to all of you, but I google'd again and found a very good (for me working) workaround. For all: I want that after navigating to a page, a timer (or something else) wait for x-seconds and during the timer is waiting, the page is loading, and after that, I want to click on the button.

First of all: the code isn't done by me. It's from https://dotnet-snippets.de/snippet/webbrowser-navigate-and-wait-seconds/15171

First declare this at the beginning:

  public delegate void NavigateDoneEvent();
        public static event NavigateDoneEvent Done;

        private static System.Windows.Forms.Timer wait;

You don't need to use this as static.

After that you need to create this function

 public static void Wait(WebBrowser Browser, string Url, double Seconds)
        {
            Browser.Navigate(Url);

            wait = new System.Windows.Forms.Timer();
            wait.Interval = Convert.ToInt32(Seconds * 1000);

            wait.Tick += (s, args) =>
            {
                if (Done != null) Done();
                wait.Enabled = false;
            };

            wait.Enabled = true;
        }

And you can call this function like:

Wait(webBrowser1, "somesite.com", 20);
            Done += afterWaitDoSomething;
MGMelli
  • 11
  • 5