问题
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!
回答1:
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);
回答2:
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;
来源:https://stackoverflow.com/questions/55939504/webbrowser-completed-doesnt-show-all-elements