I have a C# 4.0 WinForms application, which has a WebBrowser control and 2-buttons.
Clicking the first button sends a URL to the browser to navigate to a specified webSite.
Clicking the second button parses the OuterHtml of the webBrowser1.Document, looking for an "https://..." link for File Download.
The code then uses a webClient.DownloadFileAsync to pull down a file for further use in the application.
The above code successfully works, if I manually click those buttons.
In an effort to automate this for the end-user, I place the first button's click event, i.e. btnDisplayWeb.PerformClick(); in the form's Form1_Load event. This also works, allowing the webBrowser1 to populate its Document with the desired webSite.
However, I am unable to programatically click the 2nd button to acquire the web link for file download.
I have tried to place the 2nd buttons click event within the browser's DocumentCompleted event, as shown below.
private void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
btnMyUrl.PerformClick();
}
However, from what I've read on StackOverFlow and other sites, it's possible that this particular event gets called more than once, and hence it fails.
I've also attempted to loop for a number of seconds, or even use a Thread.Sleep(xxxx), but the browser window fails to populate until the sleep or timer stops.
I attempted to use the suggestions found on the following StackOverFlow site shown below.
How to use WebBrowser control DocumentCompleted event in C#?
private void webBrowser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
string url = e.Url.ToString();
if (!(url.StartsWith("http://") || url.StartsWith("https://")))
{
// in AJAX
}
if (e.Url.AbsolutePath != this.webBrowser.Url.AbsolutePath)
{
// IFRAME
}
else
{
// REAL DOCUMENT COMPLETE
}
}
However, in parsing the OuterHtml, nothing is returned in the first two sections, and in the third section, other elements are returned instead of the desired "https://..." link for File Download.
Interestingly, if I use a webBrowser1.ReadyState event, as shown below, and place a MessageBox inside DocumentCompleted, this seems to allow the browser document to complete, because after clicking the OK button, the parsing is successful.
if (webBrowser1.ReadyState == WebBrowserReadyState.Complete)
{
MessageBox.Show("waiting", "CHECKING");
btnMyUrl.PerformClick();
}
However, I then have the difficulty of finding a way to click the OK button of the MessageBox.
Is there another event that occurs after the DocumentCompleted event.
OR, can someone suggest how to programmatically close the MessageBox?
If this can be done in code, then I can perform the buttonClick() of the 2nd button in that section of code.
After finding that the addition of a MessageBox allows the webBrowser1.Document to complete, and using webBrowser1.ReadyState event within the webBrowser_DocumentCompleted event, all I needed to do, was to find a way to programmatically close the MessageBox.
Further searching on StackOverFlow revealed the following solution on the site below.
Close a MessageBox after several seconds
Implementing the AutoClosingMessageBox, and setting a time interval, closed the MessageBox and allowed my button click, i.e. btnMyUrl.PerformClick(); to successfully parse the OuterHtml and now the code works properly.
Hopefully, if someone else discovers that placing a MessageBox within the webBrowser_DocumentCompleted event allows the document to complete; the aforementioned AutoClosingMessageBox will assist them as well.
Related
I can open the link in my standard browser with this code:
public void webBrowser1_Navigating(object sender, WebBrowserNavigatingEventArgs e)
{
//cancel the current event
e.Cancel = true;
//this opens the URL in the user's default browser
Process.Start(e.Url.ToString());
}
But the problem is that IE only should be opened when a link on the webbrowser is clicked. When using this code IE also opens when I change the documenttext.
My suggestion would be to take a different approach. At the point in time immediately after the initial page has loaded in the WebBrowser control (Navigated event), you can use the webBrowser1.Document property to retrieve an HtmlDocument instance.
From this you should be able to find your link by using, for example,
http://msdn.microsoft.com/en-us/library/system.windows.forms.htmldocument.getelementbyid(v=vs.110).aspx
Then you can add an event handler to detect when this link is clicked, and in this handler, run your code to start the IE process.
I have a problem where my button click will not work whatsoever. I think all the code is right but why is nothing happening when it's clicked? Is the code right for displaying the message and is the code right for redirecting to a website/webpage? Any help much appreciated!
public delegate void myDelegate();
public event myDelegate FindInfo;
protected void btnOne_Click(object sender, EventArgs e)
{
FindInfo += new myDelegate(showFindInfoMessage);
FindInfo += new myDelegate(showWebsite);
FindInfo();
}
public void showFindInfoMessage()
{
Page.ClientScript.RegisterStartupScript(this.GetType(), "scriptkey", "<script>alert('You will now be redirected to the website!');</script>");
}
public void showWebsite()
{
string web = "https://facebook.com/";
Response.Redirect(web);
}
HTML
<asp:Button ID="btnOne" runat="server" Text="Find Info" OnClick="btnOne_Click" />
Your code looks a little strange, but it should work as you expect. I don't see anything that could immediatelly stop it from working.
Easiest things first - are there any exceptions thrown? Run the site from within VisualStudio in Debug mode, click the button on the site, and check out the "Output" window. If you see any "First Chance Exception" lines showing up after you clicked it, then try to chase and solve them, or write them down and show them to us. Make sure that those were really recorded only after you clicked the button. There might be some exceptions recorded when the site starts up. After starting up the site, be sure that the Output window stops chattering before you click the button.
Next, does any other buttons you create work as expected at all? On this page? How's that on other pages? Have you tried placing a breakpoint to see if this code runs at all? Place a breakpoint on the first line of btnOne_Click method (click there and press F9, assuming you have typical hotkeys), and also try placing some other breakpoints in other methods, like Page's constructor. Then try running your site in "debug" mode and click on the button. Check which breakpoints get triggered.
In case NO breakpoint gets hit at all, then either your VisualStudio and webserver are not configured for debugging (oops), or the page might not be compiled at all (for example, you may be running an old copy of it).
If some breakpoints are triggered but that one button handler is not, then try observing what your page does or tries to do when you click that button. If you are using any modern browser, it should have a "developer tools" panel somewhere. For example, in Chrome, press F12. In those dev-tools, find some tab or window that will show you the "Network operations". Display or refresh your page, check if some netwrok operations are captured. You should notice at least the page itself being downloaded with "200" status code. After observing that, when everything gets silent, "Clear" the log (there should be a button for that somewhere) so you get a fresh&clean view again, and press the button. Observe what happens.
If the button works on client-side, you will see a request being sent to the server. Observe the response code. Is it 200? 404? 500? All of those will mean different things. Report back with the code. Also, if there are any error (status code != 200) try to read/copy all of the details you can.
If the button and the server work ok or almost ok, then after clicking the button you would see a request sent back to the same page, followed by a status=200. However if IIS and ASPX are OK, this would run the xxx_Click handler. So probably you won't see this scenario.
If the button doesn't work at all and no requests are sent, then there's some problem with the HTML code that was rendered. Go back to the dev-tools in the browser, find a tab/window that allows you to see the raw HTML code of the site, and find that button. Check what click actions are set on it. If you don't see any, check which FORM tag is the parent of that button and check if its "method" and "action" attributes are set properly. If the method/action are generated wrong, the browser may try to send the 'click' to a wrong place, or even it may not try sending it at all.
If all of that does not show anything useful, then try ... temporarily replacing your code with something that should work in any case. Check out the example at MSDN site. Backup your page code somewhere and replace it with the example from this site. Paste all of that as the ASPX file, and remove everything from the code behind (ASPX.CS file), and run your site. This example shows a simple button and attaches one handler to that button. Check if it works. It should. Also you may observe all of the things I wrote above again. If the example does not work, then, again, I'd guess your IIS or ASP installation(s) are broken.
Your code works correctly. I put it in a test project and it redirects. If you are asking why you do not see the alert, that is because the page would need to post back to register the script, however you redirect to facebook.com before it has a chance to do so. You can register the script on page load, then call the JavaScript function to display the alert.
public partial class _Default : Page
{
protected void Page_Load(object sender, EventArgs e)
{
showFindInfoMessage();
}
public delegate void myDelegate();
public event myDelegate FindInfo;
protected void btnOne_Click(object sender, EventArgs e)
{
FindInfo += new myDelegate(showFindInfoMessage);
FindInfo += new myDelegate(showWebsite);
FindInfo();
}
public void showFindInfoMessage()
{
Page.ClientScript.RegisterOnSubmitStatement(this.GetType(), "scriptkey", "alert('You will now be redirected to the website!')");
}
public void showWebsite()
{
string web = "https://facebook.com/";
Response.Redirect(web);
}
}
I have a webpage, and an input button on it. Clicking on this button, in a specific div are loaded some data. My problem is that I can't catch this data.
The following code is my attempt to solve this problem, but without success.
private void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
HtmlElement div_result = webBrowser1.Document.GetElementById("div_result");
div_result.AttachEventHandler("onpropertychange", new EventHandler(resultEventHandler));
}
private void resultEventHandler(object sender, EventArgs e)
{
MessageBox.Show("Loaded");
}
If I click on input button, div's content is modified, but the resultEventHandler does not fire.
So, I have two questions:
Where is my fault in this code?
Is there a "normal way"(I mean without using timers or Aplication.DoEvents()) to work with ajax using WebBrowser control in C#?
Changing the innerText or innerHTML of child elements will not cause the onpropertychange event to fire for the parent element.
I cannot tell why HtmlElement events do not work for you. But I had the same problem and resolved it by using COM wrappers:
mshtml.HTMLDocumentClass doc = (mshtml.HTMLDocumentClass)webBrowser1.Document.DomDocument;
mshtml.IHTMLElement2 div_result = (mshtml.IHTMLElement2)doc.getElementById("div_result");
mshtml.HTMLElementEvents2_Event events = (mshtml.HTMLElementEvents2_Event)div_result;
events.onpropertychange += resultEventHandler;
This may be too late but here it is anyways in case you are still wondering:
1 - HtmlElement div_result = webBrowser1.Document.GetElementById("div_result");
Line #1 executes when the web page has loaded and the DocumentCompleted event has been called by the browser. Inside the event handler you first retrieve a pointer to the DOM element "div_result" and you assign an HtmlElement type variable named div_result.
2 - div_result.AttachEventHandler("onpropertychange", new EventHandler(resultEventHandler));
Line #2 - registers the "onpropertychange" event and assigns the method resultEventHandler as the listener method.
Every time you click on the button on your web page, the button (which I assume) is in a form that gets submitted which causes the web page to load; by the way you did not specify which post method you are using when the button is clicked (get or post). When the web page download completes and the DOM element tree is constructed your DocumentCompleted event is called. You're DocumentCompleted event handler method performed the instructions described above.
Every time you click your button, you web page is reloaded and you reassign the event listener for the onpropertychange event. You are only assigning the event listener. The event will never be called. It will just be defined every time you click the button. You have a classic which came first chicken, or egg problem. But in your case, your chicken is the button click event causing the DocumentCompleted method to run which resets the state of all variables in the method, and your egg is wanting a pointer to the DIV element's onpropertychange event before the button is clicked on the web page . How do you assign an event listener to an htmlelement before you can get a pointer from the DOM which has not been constructed? Put a Boolean flag variable in the class that contains the DocumentCompleted method and set its initial state. Move the div_result variable outside of the DocumentCompleted method to increase its scope and to save its state across a button click event. This way, you will get a pointer to your div element and set its onpropertychange event listener the first time the web page is downloaded. Add a test if you just want to set a pointer to the DIV element's onpropertychange event listener just once (I put one in the sample code below), and the next time you click your button, your event will fire. NOTE! Make sure you do not add, or delete any element to your web page after you store a pointer to any of the web page's elements or their events. Otherwise you will have to reparse the DOM to get a pointer to the Element's new position in the DOM tree.
//See below:
class SomeClass
{
bool DocumentHasLoaded = false;
HtmlElement div_result = null;
//Constructor and other methods go here....
//Then change your DocumentCompleted method to look like this:
private void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
if (DocumentHasLoaded == false) // I prefer using a ! before the variable instead
{
DocumentHasLoaded = true; // You will have to create your own appropriately timed mechanism to reset this variable's state should you want to execute the whole process again.
div_result = webBrowser1.Document.GetElementById("div_result");
div_result.AttachEventHandler("onpropertychange", new EventHandler(resultEventHandler));
}
}
}
In order to answer your second question I require more information about the data that is loaded in the DIV; e.g. where it comes from and what type it is plus any other pertinent information you can think of.
This may come across as incredibly stupid, but I cannot figure out if:
I am an idiot
I have misunderstood something
The MS Web Browser control is bugged
I prefer to think that it is the latter.
I have a Web Browser control in a WinForms user control. It has been added to the control at design time, and in theory, in the Load event of the control it should navigate to Google.
Seems straightforward.
However.
public partial class TVHost : UserControl
{
public TVHost()
{
InitializeComponent();
}
private void TVHost_Load(object sender, EventArgs e)
{
webBrowser1.Navigate("http://google.co.uk");
}
}
This doesn't work. No error, just nothing. Inserting a breakpoint/debug lines shows me that the Load event doesn't even get called.
I decided at this point to check that the Load event is being set correctly in the Designer.cs file.
this.Load += new System.EventHandler(this.TVHost_Load);
Seems legit.
If I remove the web browser control from the form, the load event fires.
I don't understand this one bit, how can a control prevent a method which uses it from firing in the first place?
Moving on, I found this:
http://social.msdn.microsoft.com/Forums/en-US/Vsexpressvcs/thread/d6e427b2-9cc9-4318-bb05-11363025e3f7/
TL;DR for the link is as follows: "Load won't work if you have a webbrowser on the form which is set to Visible = true"
So sure as hell, if I change the default visibility of the webbrowser to false, the load event of the control fires. I can work around the problem by setting the visibility of the browser in the load event.
private void TVHost_Load(object sender, EventArgs e)
{
webBrowser1.Visible = true;
webBrowser1.Navigate("http://google.co.uk");
}
Very odd.
Whilst this "fix" works, I find it incredibly hacky and was wondering if anybody has any explaination for this behaviour?
Amazingly I have found this bug in MS Connect, left over from 2005 - http://connect.microsoft.com/VisualStudio/feedback/details/116535/when-adding-a-webbrowser-control-to-a-user-control-the-load-will-not-fire#
From the discussion in the Connect bug you linked to:
For now, if you want to get the Load event to fire, you can set the URL property of the WebBrowser control in the property grid. The URL can be anything you want, even about:blank if you don't want it to start with a page loaded.
So if you go into the designer and set the WebBrowser's Url property to the string about:blank (which tells the WebBrowser to load an empty page), then your user control should start getting its Load event again.
Background: I am customizing an existing ASP .NET / C# application. It has it's own little "framework" and conventions for developers to follow when extending/customizing its functionality. I am currently extending some of it's administrative functionality, to which the framework provides a contract to enforce implementation of the GetAdministrationInterface() method, which returns System.Web.UI.Control. This method is called during the Page_Load() method of the page hosting the GUI interface.
Problem: I have three buttons in my GUI, each of which have been assigned an Event Handler. My administration GUI loads up perfectly fine, but clicking any of the buttons doesn't do what I expect them to do. However, when I click them a second time, the buttons work.
I placed breakpoints at the beginning of each event handler method and stepped through my code. On the first click, none of the event handlers were triggered. On the second click, they fired.
Any ideas?
Example of Button Definition (within GetAdministrationInterface)
public override Control GetAdministrationInterface()
{
// more code...
Button btn = new Button();
btn.Text = "Click Me!";
btn.Click += new EventHandler(Btn_Click);
// more code...
}
Example of Event Handler Method Definition
void Btn_Click(object sender, EventArgs e)
{
// Do Something
}
Page_Load Method that calls GetAdministrationInterface
protected void Page_Load(object sender, System.EventArgs e)
{
if (!Page.IsAsync)
{
List<AdministrationInterface> interfaces = <DATABASE CALL>;
foreach(AdministrationInteface ai in interfaces)
{
placeholderDiv.Controls.Add(ai.GetAdministrationInterface());
}
}
}
Good grief! I knew it was going to be something this stupid. Purely my fault of course and my lack of knowledge in ASP .NET.
After doing a multitude of Google searches and eventually being blocked by Google on suspicion of being a bot running automated scripts, I managed to squeeze in one last search in and stumbled across this article. Already at the point of giving up, I tried my best to read the article without skipping 10 lines at a time or looking for pretty pictures. In the section titled Assigning IDs to Dynamically Created Controls, I read these magical and most joyful words:
If you view the source HTML before you click the not-working button and after you have clicked it, you will notice a small difference. The buttons have different HTML IDs before and after the post-back. I got ctl04 and ctl05 before the post-back and ctl02 and ctl03 after the post-back.
ASP.NET button recognizes events by checking for a value for its ID in the Request.Form collection. (In truth it happens differently and controls do not check Request.Form collection by themselves. Page passes post data to controls by their IDs and to controls that are registered to be notified about post data). ASP.NET does not fire the Click event, because the button's ID has changed between the post-backs. The button you have clicked and the button you see after are different buttons for ASP.NET.
Sure enough, when I viewed the HTML the first time, my button had the ID ctl04$ctl36. After clicking the button, my button had the ID ctl04$ctl33.
So there you have it! All I had to do was set the ID on the buttons and presto! My event handlers are now being called!
Sample Solution:
public override Control GetAdministrationInterface()
{
// more code...
Button btn = new Button();
btn.Text = "Click Me!";
// !!THE BANE OF MY EXISTENCE!!
btn.ID = "The_Bane_of_My_Existence";
// !!THE BANE OF MY EXISTENCE!!
btn.Click += new EventHandler(Btn_Click);
// more code...
}
What a great way to spend two days...
I had the same problem, but the accepted answer here was not causing it. I had a text box and a search button, and clicking the button the first time didn't perform the search. The event handler of the button wasn't being hit. But clicking the button a second time did trigger the event on the server. Here is why:
If you have an <asp:Textbox> with its AutoPostBack set to true, after typing in the text box and then moving to click a button, the text box causes a post-back immediately the moment it loses focus. So the click even of the button doesn't count (the page is already posted-back as a result of the text box's event). That's why when you click the button a second time, it works because the text box is not involved in the second post-back.
Set the AutoPostBackproperty of the <asp:Textbox> to false to fix this issue.
A quick fix is to set an ID to the ASCX control your are loading on a page. For example, if your code is like this:
UserControl SpecsControl = (UserControl)Page.LoadControl("../name.ascx");
SpecsContainer.Controls.Add(SpecsControl);
then you need to add a line (before Controls.Add):
SpecsControl.ID = "Aribtrary_Name";
Then your handler method is fired at the first click.
I was facing the same problem. My button froze after my first click. For me this annoying problem got solved when I disabled the button's EnableViewState attribute.
For me it was the UpdatePanel , my Button and my TextBox were both inside an UpdatePanel , so when I post-back , it caused some weird behavior . It took it outside of the UpdatePanel and that fixed it .
Even i had the same problem. the cause was "localhost:1656/secure/login.aspx?ReturnUrl=%2f".
if the request contain %2f as query string, the first post will not be succeeded even though "%2f" is representing "/".
one way to avoid this by having a condition check in pageload
protected void Page_Load(object sender, EventArgs e)
{
string queryString = Request.QueryString.ToString();
if(queryString == "ReturnUrl=%2f")
{
Response.Redirect("/secure/login.aspx");
}
}
Whilst its hard to know exactly without seeing the full Page_load method it does smell a little bit like the event handlers are not hooking up until the page is reloaded.
eg:
if (IsPostBack) {
// Add handlers here ...
}
I had same problem. And I searched on internet i didnt find a solution. After that i found sample code and I used it. It worked for me. Web site link is below:
http://www.c-sharpcorner.com/UploadFile/abhikumarvatsa/calling-an-Asp-Net-C-Sharp-method-web-method-using-javascript/