DocumentCompleted not firing twice - c#

Scraping a web page. The page loads and calls a DocumentCompleted handler. Inside that handler, I invoke a java method to set a date and then invoke a click to get the new data (via POST). This all works correctly except that the DocumentCompleted handler is only called once. The POST that goes back and "gets" a new page doesn't cause the handler to fire a second time.
I tried adding multiple handlers, removing the first and adding a second handler in the first handler. Didn't work. Also ran this as Administrator, didn't change anything.
Anyone have thoughts on how to proceed? I guess I can wait 60 seconds for it to load and then grab the text but that seems clunky.
public void FirstHandler(object sender,
WebBrowserDocumentCompletedEventArgs e)
{
WebBrowser wb = ((WebBrowser)sender);
string url = e.Url.ToString();
if (!(url.StartsWith("http://")) || url.StartsWith("https://"))
{
// in AJAX
}
if (e.Url.AbsolutePath != webBrowser.Url.AbsolutePath)
{
// IFRAME Painting
}
else
{
// really really complete
wb.DocumentCompleted -= FirstHandler;
wb.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(SecondHandler);
HtmlElement webDatePicker = wb.Document.GetElementById("ctl00_WebSplitter1_tmpl1_ContentPlaceHolder1_dtePickerBegin");
string szJava = string.Empty;
szJava = "a = $find(\"ctl00_WebSplitter1_tmpl1_ContentPlaceHolder1_dtePickerBegin\"); a.set_text(\"5/20/2017\");";
object a = wb.Document.InvokeScript("eval", new object[] { szJava });
if (webDatePicker != null)
webDatePicker.InvokeMember("submit");
HtmlElement button = wb.Document.GetElementById("ctl00$WebSplitter1$tmpl1$ContentPlaceHolder1$HeaderBTN1$btnRetrieve");
if (button != null)
{
button.InvokeMember("click");
}
}
}
public void SecondHandler(object sender,
WebBrowserDocumentCompletedEventArgs e)
{
WebBrowser wb = ((WebBrowser)sender);
string url = e.Url.ToString();
string d = string.Empty;
if (!(url.StartsWith("http://")) || url.StartsWith("https://"))
{
// in AJAX
}
if (e.Url.AbsolutePath != webBrowser.Url.AbsolutePath)
{
// IFRAME Painting
}
else
{
d = wb.DocumentText;
System.IO.File.WriteAllText("Finally.htm", d);
wb.DocumentCompleted -= SecondHandler;
}
_fired = true;
}

Related

C# Wait for Web Page to Load Before Scraping

I am trying to make a Windows Forms app that logs in another web application, navigates for a few steps (clicks) until it reaches a specific page and then scrape some info (names and addresses).
The problem is that I am using the DocumentCompletedEventHandler in order to have a page loaded before I execute the code for navigating to the next page (in order to reach the final web page).
When it fires, DocumentCompletedEventHandler fires multiple times.
When I reach the loggin page, it enters the credentials and then the message "Page loaded!" appears multiple times.
I press enter, it appears again.
Then it navigates to the next page and with that new page I have the same problem.
how can I make DocumentCompletedEventHandler to fire only once and not multiple times?
private void loadEvent(object sender, WebBrowserDocumentCompletedEventArgs e)
{
MessageBox.Show("Page loaded!");
}
private void loadLogin(object sender, WebBrowserDocumentCompletedEventArgs e)
{
var inputElements = webBrowser1.Document.GetElementsByTagName("input");
foreach (HtmlElement i in inputElements)
{
if (i.GetAttribute("name").Equals("utilizator"))
{
i.InnerText = textBox1.Text;
}
if (i.GetAttribute("name").Equals("parola"))
{
i.Focus();
i.InnerText = textBox2.Text;
}
}
var buttonElements = webBrowser1.Document.GetElementsByTagName("input");
foreach (HtmlElement b in buttonElements)
{
if (b.GetAttribute("name").Equals("Intra"))
{
b.InvokeMember("Click");
}
}
webBrowser1.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(loadEvent);
var inputElements1 = webBrowser1.Document.GetElementsByTagName("input");
foreach (HtmlElement i1 in inputElements1)
{
if (i1.GetAttribute("id").Equals("headerqstext"))
{
i1.Focus();
i1.InnerText = textBox3.Text;
}
}
var buttonElements1 = webBrowser1.Document.GetElementsByTagName("button");
foreach (HtmlElement b1 in buttonElements1)
{
if (b1.GetAttribute("title").Equals("Caută"))
{
b1.InvokeMember("Click");
}
}
webBrowser1.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(loadEvent);
}
private void Button1_Click(object sender, EventArgs e)
{
webBrowser1.Navigate("http://10.1.104.23/ecris_cdms/");
webBrowser1.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(loadLogin);
}
}
}
try this :)
Uri last = null;
private void CompleteResponse(object sender, WebBrowserDocumentCompletedEventArgs e)
{
if (!(last != null && last != e.Url))
return;
//your code here
}

Can I detect failure on mshtml.IHTMLElement.click() call?

Can I determine if the click call was successfully? I'm debuggin an application that click on button (see below code) sometimes it seems fail to do so, I'd liek to determine whatever the click was successfully.
HtmlElement button = ...;
IHTMLElement nativeElement = button.DomElement as IHTMLElement;
nativeElement.click();
Have you considered adding an event handler for the click event for that particular HTMLElement? You could do something along these lines :
bool shouldfire = false;
bool didFire = false;
private void yourMethod()
{
HtmlElement button = ...; //however you are getting this element
button.Click +=button_Click;
IHTMLElement nativeElement = button.DomElement as IHTMLElement;
nativeElement.click();
shouldfire = true;
}
private void button_Click(object sender, HtmlElementEventArgs e)
{
didFire = true;
}
private void yourOtherMethod()
{
if (shouldfire != didFire)
{
//do something
}
}

Winforms Webbrowser control URL Validation

I am trying to validate a winform web browser control url when a button is clicked. I would like to see if the web browser's current url matches a certain url. When I try to run this code the program freezes
private void button_Click(object sender, EventArgs e)
{
// Check to see if web browser is at URL
if (webBrowser1.Url.ToString != "www.google.com" || webBrowser1.Url.ToString == null)
{
// Goto webpage
webBrowser1.Url = new Uri("www.google.ca");
}
else {
webBrowser1.Document.GetElementById("first").InnerText = "blah";
webBrowser1.Document.GetElementById("second").InnerText = "blah";
}
}
Here you go.
private void button1_Click(object sender, EventArgs e)
{
webBrowser1.Url = new Uri("https://www.google.ca");
// Check to see if web browser is at URL
if (webBrowser1.Url != null)
{
if (webBrowser1.Url.ToString() != "https://www.google.com" || webBrowser1.Url.ToString() == null)
{
// Goto webpage
webBrowser1.Url = new Uri("www.google.ca");
}
else
{
webBrowser1.Document.GetElementById("first").InnerText = "blah";
webBrowser1.Document.GetElementById("second").InnerText = "blah";
}
}
}
1) Please use the schema with the URL.
2) Use ToString() as a function.

Cancel opening link in browser

In my Windows phone application I use RichTextBox element
I have a hyperlink on it, and when user click on it there is a dialog: Do you want to open this link in exteranl browser. If user say no, external browser shouldn't be opened. I cancel navigation but in any case - external browser opens. How can I cancel opening link in browser?
//Constructor
static Helper()
{
var phoneApplicationFrame = Application.Current.RootVisual as PhoneApplicationFrame;
if (Application.Current.RootVisual as PhoneApplicationFrame != null)
{
phoneApplicationFrame.Navigating += new NavigatingCancelEventHandler(NavigationService_Navigating);
}
}
link.Foreground = new SolidColorBrush(Colors.Blue);
link.MouseOverForeground = new SolidColorBrush(Colors.Blue);
link.TargetName = "_blank";
var linkText = new Run() { Text = linkDesc };
link.Inlines.Add(linkText);
link.Click += new RoutedEventHandler(NavidateTo);
private static void NavidateTo(object sender, RoutedEventArgs routedEventArgs)
{
if (MessageBox.Show(
Constants.BrowserNavigating,
"",
MessageBoxButton.OKCancel) == MessageBoxResult.Cancel)
{
StateManager.Set("ExternalBrowser", "true");
}
else
{
StateManager.Set("Browser", "true");
}
}
public static void NavigationService_Navigating(object sender, NavigatingCancelEventArgs e)
{
var res = StateManager.Get("ExternalBrowser");
if (res != null)
{
StateManager.Remove("ExternalBrowser");
e.Cancel = true;
}
}
Rather than have the HyperlinkButton open the link itself, don't specify the NavigationUri but handle the Tap event yourself.
In the eventhandler ask the question and only open the browser if they say yes.
This will be much simpler than trying to cancel something that is already in progress.

Dynamically added ImageButton Command event not firing until second click

I have a page where I'm adding ImageButtons dynamically. I first set the OnClientClick of the buttons to simply show a popup of the image enlarged and return false for no postback.
I have a button on the page to set the "primary image" so when this button is clicked I set a property called _IsSettingPrimaryPhotoMode = true, call the function to recreate the ImageButtons, and when creating the ImageButtons if this property is true instead of adding an OnClientClick, I hook up a CommandEventHandler so I can tell which button was clicked by reading the CommandArgument.
The problem is the event handler won't fire on the first click of the image but only on the second click and thereafter. I've also moved the code from Page_Load to OnInit and I load the ImageButtons on every postback.
I save the _IsSettingPrimaryPhotoMode to the Session.
private bool _IsSettingPrimaryPhotoMode {
get {
bool result = false;
if(Session[ConstantsWeb.Session.IS_DELETE_IMAGE_MODE] != null) {
result = Convert.ToBoolean(Session[ConstantsWeb.Session.IS_SETTING_PRIMARY_IMAGE_MODE]);
}
return result;
}
set {
Session[ConstantsWeb.Session.IS_SETTING_PRIMARY_IMAGE_MODE] = value;
}
}
The page OnInit
protected override void OnInit(EventArgs e) {
base.OnInit(e);
if(!IsPostBack) {
_IsSettingPrimaryPhotoMode = false;
}
_LoadGalleryImages();
}
}
The _LoadGalleryImages method
private void _LoadGalleryImages() {
PhotoGalleryImageCollection images = PhotoGalleryImages.GetPhotoGalleryImages();
foreach(PhotoGalleryImage image in images) {
ImageButton displayImage = new ImageButton();
Panel panel = new Panel();
panelPhotoContainer.Controls.Add(panel);
displayImage.ImageUrl = "some URL";
if(!_IsSettingPrimaryPhotoMode) {
displayImage.OnClientClick = "showPopup(); return false;";
}
else {
displayImage.Command += new CommandEventHandler(displayImage_Command);
displayImage.CommandName = "ImageButton" + image.PhotoGalleryImageId.ToString();
displayImage.CommandArgument = image.PhotoGalleryImageId.ToString();
}
panel.Controls.Add(displayImage);
}
}
btnSetPrimaryPhoto_Click
protected void btnSetPrimaryPhoto_Click(object sender, EventArgs e) {
// if I don't call this, duplicate controls will be added since they were added
// from OnInit calling _LoadGalleryImages();
panelPhotoContainer.Controls.Clear();
_IsSettingPrimaryPhotoMode = true;
// reload since _IsSettingPrimaryPhotoMode has now changed
_LoadGalleryImages();
}
What am I doing wrong?
I suppose the issue can be caused by the fact you haven't set IDs of the dynamically created controls. It's quite important, as it's used in the process of firing the post back events. Value of the ID for each of the controls should be constant and not change between postbacks.
You can try to modify your _LoadGalleryImages() method like this:
private void _LoadGalleryImages() {
PhotoGalleryImageCollection images = PhotoGalleryImages.GetPhotoGalleryImages();
int imageCtrlCounter = 0;
foreach(PhotoGalleryImage image in images) {
ImageButton displayImage = new ImageButton() { ID = String.Format("myDisplayImage{0}", imageCtrlCounter) };
Panel panel = new Panel();
panelPhotoContainer.Controls.Add(panel);
displayImage.ImageUrl = "some URL";
if(!_IsSettingPrimaryPhotoMode) {
displayImage.OnClientClick = "showPopup(); return false;";
}
else {
displayImage.Command += new CommandEventHandler(displayImage_Command);
displayImage.CommandName = "ImageButton" + image.PhotoGalleryImageId.ToString();
displayImage.CommandArgument = image.PhotoGalleryImageId.ToString();
}
panel.Controls.Add(displayImage);
imageCtrlCounter++;
}
}
It has to be something related to the initial event wireup because the problem only happens the first time. What's different about that time is that _LoadGalleryImages is called twice (once in the init and once in the button click event handler) so I think that something is not getting cleaned up there when you clear the container panel and call _LoadGalleryImages again in the button's click handler.
Why not try this alternative:
Only call LoadImageGalleries once per page cycle (in the init).
Instead of clearing the controls and calling LoadGalleryImages again in the same postback (in the button click event), on the button click call a method that iterates through the image controls you already created when LoadGalleryImages was called and adjust them:
1) Remove the onclientclick (clear it out).
2) Attach the event.
#swannee
Actually, your method did work after I thought more about it. I do now call _LoadGalleryImages on every OnInit. I realize this is a lot of duplicate code that could be consolidated.
New _LoadGalleryImages
private void _LoadGalleryImages() {
PhotoGalleryImageCollection images = PhotoGalleryImages.GetPhotoGalleryImages();
foreach(PhotoGalleryImage image in images) {
Panel panel = new Panel();
panelPhotoContainer.Controls.Add(panel);
ImageButton displayImage = new ImageButton();
panel.Controls.Add(displayImage);
displayImage.ID = string.Format("ImageButton{0}", image.PhotoGalleryImageId);
displayImage.ImageUrl = "Some URL";
displayImage.AlternateText = displayImage.ToolTip = image.ImageName;
if(!_IsSettingPrimaryPhotoMode) {
displayImage.OnClientClick = "showPopup(); return false;";
}
else {
// handles the image button command wireup
displayImage.Command += new CommandEventHandler(displayImage_Command);
displayImage.CommandArgument = image.PhotoGalleryImageId.ToString();
}
}
}
I added a new method as you suggested to find the controls since they've already been created in OnInit and I just need to find them after the button click and clear the OnClientClick.
private void _LoadSelectPrimaryImages() {
PhotoGalleryImageCollection images = PhotoGalleryImages.GetPhotoGalleryImages();
foreach(PhotoGalleryImage image in images) {
Control control = panelPhotoContainer.FindControl(string.Format("ImageButton{0}", image.PhotoGalleryImageId));
if(control != null) {
ImageButton displayImage = (ImageButton)control;
displayImage.OnClientClick = "";
}
}
}
I also have a cancel button to return the image buttons to the way they were before to show the popup.
private void _ResetGalleryImages() {
PhotoGalleryImageCollection images = PhotoGalleryImages.GetPhotoGalleryImages(_photoGalleryId, false, true);
foreach(PhotoGalleryImage image in images) {
Control control = panelPhotoContainer.FindControl(string.Format("ImageButton{0}", image.PhotoGalleryImageId));
if(control != null) {
ImageButton displayImage = (ImageButton)control;
displayImage.ImageUrl = "Original URL";
displayImage.OnClientClick = "showPopup(); return false;";
}
}
}
and two page button clicks
protected void btnSetPrimaryPhoto_Click(object sender, EventArgs e) {
_IsSettingPrimaryPhotoMode = true;
_LoadSelectPrimaryImages();
}
protected void btnCancelSetPrimaryPhoto_Click(object sender, EventArgs e) {
_IsSettingPrimaryPhotoMode = false;
_ResetGalleryImages();
}
Someone said in a response earlier...looks like the response was removed...to clear the controls in _LoadGalleryImages such as:
private void _LoadGalleryImages() {
panelPhotoContainer.Controls.Clear();
PhotoGalleryImageCollection images = PhotoGalleryImages.GetPhotoGalleryImages();
foreach(PhotoGalleryImage image in images) {
ImageButton displayImage = new ImageButton();
Panel panel = new Panel();
panelPhotoContainer.Controls.Add(panel);
displayImage.ImageUrl = "some URL";
if(!_IsSettingPrimaryPhotoMode) {
displayImage.OnClientClick = "showPopup(); return false;";
}
else {
displayImage.Command += new CommandEventHandler(displayImage_Command);
displayImage.CommandName = "ImageButton" + image.PhotoGalleryImageId.ToString();
displayImage.CommandArgument = image.PhotoGalleryImageId.ToString();
}
panel.Controls.Add(displayImage);
}
}
which also works but I think that may be more inefficient than your method, #swannee. Thanks!

Categories

Resources