0

I'm using Visual Studio Community in C# (.Net 4.5). I have a simple form, with one button and one webBrowser control. I want to check if "tremblay jean" has a trademark registered in his name in Canada (I know he has two). So when I click my button I load the trademarks search page in my webBrowser control, I wait for it to be complete, then I insert his name in their textbox and click their button. If I pause the program using a MessageBox.Show after loading the page, it works, there's two documents found. But if I don't pause the program using a MessageBox it doesn't work. It gives me 500 results, unrelated to "tremblay jean". So the line of code waiting for the ReadyState to be Complete doen't seem to work. Does anyone know why?

private void button1_Click(object sender, EventArgs e)
    {
        string website = "http://www.ic.gc.ca/app/opic-cipo/trdmrks/srch/home?lang=eng";
        webBrowser1.Navigate(website);
        while (webBrowser1.ReadyState != WebBrowserReadyState.Complete) Application.DoEvents();
        MessageBox.Show(webBrowser1.ReadyState.ToString()); // to pause the program
        webBrowser1.Document.GetElementById("search-crit-1").SetAttribute("value", "tremblay jean");
        HtmlElementCollection elc = webBrowser1.Document.GetElementsByTagName("button");
        foreach (HtmlElement el in elc)
        {
            if (el.GetAttribute("type").Equals("submit"))
            {
                if (el.InnerText == " Search ")
                {
                    el.InvokeMember("Click"); //comment this line to see if textbox is filled
                    break;
                }
            }
        }
    }
Richard L.
  • 5
  • 1
  • 5
  • Subscribe the `DocumentCompleted` event. There might be hiccups if the page contains iframes. See [How to use WebBrowser control DocumentCompleted event](https://stackoverflow.com/questions/840813/how-to-use-webbrowser-control-documentcompleted-event-in-c) as an example. – Jimi Apr 14 '18 at 19:26
  • Javascript is the more typical hazard today. You can't find out when it is "done" modifying the page, unless it changes the DOM in a recognizable way. In which case you'd have a shot it at with a Timer. Consider asking the web site owner about a web service api. – Hans Passant Apr 14 '18 at 22:24
  • DocumentCompleted event? Won't that do the same thing? A Timer? Like a delay of some sort? How would I code a Timer of, let's say, one second? By the way, is something wrong with my code or is it the ReadyState isn't working properly? Sorry, I'm new at this... – Richard L. Apr 15 '18 at 01:21
  • You can accomplish the same result in many ways. Since you have a choice, you could choose the one that lets you test and verify the results of your process. @Hans Passant told you about JavaScript, suggesting it's implications. I told about iFrames. I told because that page contains 1 iFrame. This combination may alter the result in some cases. Not really in this one, because handling the WebBrowser `DocumentCompleted` is enough. And lets you test what that page gives you back quite easily. One of the results you could have tested, is the name of the button you're trying to click. – Jimi Apr 15 '18 at 15:39
  • https://stackoverflow.com/a/3239313/17034 – Hans Passant Apr 15 '18 at 16:48
  • Thanks for responding. First, I can't use the name of the button I am trying to click because it doesn't have a name or an Id. Here's the html coding for the button: . Secondly, I will try to find out how to use DocumentCompleted, but, as I said, I wonder if it isn't the same as using ReadyState. – Richard L. Apr 15 '18 at 16:49
  • Ok, I tried using the DocumentCompleted event instead of ReadyState, same result. Any more ideas please? – Richard L. Apr 15 '18 at 17:39
  • The missing name is enough, because the other (wrong) buttons have a name. If you want, I can post some code to handle this. Also, adapting the code Hans linked can get you the results you need. (Remember to prefix nicknames with a "@" if you want to ping someone). – Jimi Apr 15 '18 at 19:39
  • As you said earlier @Jimi (Thanks for the @ hint), you can accomplish the same result in many ways. My method of clicking the button might look weird, but it works. The problem wasn't there but I still would like to see your (a better) solution. Now as for Hans's code, I tried the two solutions he proposed, in the first (hard) one, it said "Now it's really done" three times, but didn't fill in the textBox. In the second (easy) one, it said it once, and still didn't fill the textBox. Weird huh? – Richard L. Apr 16 '18 at 16:54
  • Programmatically clicking a WebForm button is not weird at all. If you search SO, you'll find hundreds of these questions. It's common practice, I'ld say. I was referring to your implementation. It makes it a bit difficult to test the results you're receiving (debugging the code). Also, handling the `DocumentCompleted` event is the usual (tested) way to accomplish this. I'll post a method that handles this kind of process (adapted to you case). – Jimi Apr 16 '18 at 17:06

1 Answers1

0

The first thing to do, when you're using a WebBrowser control, is to initialize it with this html string:

<meta http-equiv='x-ua-compatible' content='IE=edge,chrome=1'>

This allows to set the compatibility mode of the control's underlying activex (Internet Explorer) to the most recent locally available version.

With webBrowser1.ScriptErrorsSuppressed = true;, the scripting error popup is disabled.
It's a just in case measure.

Then, subscribe the DocumentCompleted event, that will raise when the page has been loaded. As already noted in the comments, this event might be raised more than once, because of the interaction of Scripting and IFrame.
The WebBrowser.ReadyState is used to verify that page is indeed completed.

It's true that, sometimes, the inner scripting can cause some trouble here, but since this is not the case, I'll leave it as a side note.

One other thing you'll notice is that the DocumentCompleted event is unsubscribed after the WebForm button is clicked. This is done to avoid further notifications from the WebBrowser, as the needed action is already been performed and no further action is required on other pages.
So, the event will be active only when you'll be requesting new results to the server (e.g. clicking your UI Search button).

Here, the private string SearchName; is a placeholder for a procedure the defines the new search criteria.

private string SearchName;
private void button1_Click(object sender, EventArgs e)
{
    SearchName = "tremblay jean";
    webBrowser1.ScriptErrorsSuppressed = true;
    webBrowser1.Navigate("");
    webBrowser1.Document.Write("<!DOCTYPE html><head><meta http-equiv='x-ua-compatible' content='IE=edge,chrome=1'></head>");
    webBrowser1.Navigate("http://www.ic.gc.ca/app/opic-cipo/trdmrks/srch/home?lang=eng");
    webBrowser1.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(this.WBDocCompleted);
}

protected void WBDocCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
    WebBrowser browser = ((WebBrowser)sender);
    if (browser.ReadyState == WebBrowserReadyState.Complete)
    {
        if (browser.Document != null)
        {
            browser.Document.GetElementById("search-crit-1").SetAttribute("value", this.SearchName);
            foreach (HtmlElement button in browser.Document.GetElementsByTagName("button"))
            {
                if (button.GetAttribute("type") == "submit" && button.Name == "")
                {
                    browser.DocumentCompleted -= this.WBDocCompleted;
                    button.InvokeMember("click");
                    break;
                }
            }
        }
    }
}
Jimi
  • 29,621
  • 8
  • 43
  • 61
  • @Richard L. I'm glad you find it useful. Could you get it to work? – Jimi Apr 18 '18 at 15:28
  • not yet, I waiting to find time to study your code line by line and understand what it does (or not). In the meantime I have made myself a wait() function that reads the clock and reads it again until a number of seconds has passed. So when I load a page I wait a second or two or three, depending on the case. I know this is a bad solution and I will need to fix this, because it may take 2 seconds here and now, but what will happen when someone else uses the program elsewhere? Chaos! So I'll need to study your code, very soon, and will tell you what happened. Thanks... – Richard L. Apr 20 '18 at 20:19
  • @Richard L. Since you're studying it, it's not a bad solution, it's learning. If you have questions about the code I've posted, no problem, post a comment here and I'll give you some details. – Jimi Apr 20 '18 at 20:28
  • I meant the function I have created to wait a certain number of seconds before continuing to the next step is a bad solution. Not your code... – Richard L. Apr 20 '18 at 20:56
  • @Richard L. Yes, I got it. I meant, if you're studying different solutions, there's nothing bad about it. And, if you need some informations about what I wrote, just ask. – Jimi Apr 20 '18 at 20:59