My problem is simple yet i cannot figure out why it's not working inside of if/loop. Here are some examples:
Working one:
private void button1_Click(object sender, EventArgs e)
{
webBrowser1.Document.GetElementById("login").SetAttribute("value", "something");
webBrowser1.Document.GetElementById("password").SetAttribute("value", "something");
}
Non working one:
if (webBrowser1.IsBusy == false)
{
webBrowser1.Document.GetElementById("login").SetAttribute("value", "something");
webBrowser1.Document.GetElementById("password").SetAttribute("value", "something");
}
No matter what the "if" statement is, it's not working. Also tried with "for", also tried to get it out of the loop of "for", i still get this error: "Object reference not set to an instance of an object."
I'm taking a guess here because of the limited information.
I think you are trying to modify the page right after setting the Url property. The webpage will not yet be loaded then so the controls you are getting are not available yet.
Try adding the code to the DocumentCompleted event of the WebBrowser. This event will be triggered right after the document is fully loaded and the elements will be available then.
private void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
var loginControl = webBrowser1.Document.GetElementById("login");
var passwordControl = webBrowser1.Document.GetElementById("password");
if (loginControl != null)
loginControl.SetAttribute("value", "something");
if (passwordControl != null)
passwordControl.SetAttribute("value", "something");
}
more: http://msdn.microsoft.com/en-us/library/system.windows.forms.webbrowser.documentcompleted.aspx
Update
Your assumption about IsBusy is not completely correct. It starts out false when nothing is loaded. settings the Url property will not immediately set it to true.
For an alternative you requested you could use the ReadyState property that will have the value of WebBrowserReadyState.Complete when loading is done. you could use the following example. Although i personally don't like it as there is the risk of endless loop when the page can't load for some reason. I would advise to use the DocumentCompleted if possible and i modified that example to correctly handle non-login pages as well.
while (webBrowser1.ReadyState != WebBrowserReadyState.Complete)
{
Thread.Sleep(0);
Application.DoEvents();
}
Related
I have a custom error handler for an asp.net site.
void Application_Error(object sender, EventArgs e)
{
// Code that runs when an unhandled error occurs
//if (System.Configuration.ConfigurationManager.AppSettings["ProductionMode"] == "Yes")
#if (!DEBUG)
Server.Transfer("~\\GlobalExceptionHandler.aspx");
#endif
}
It works fine and dandy when retrieving exception information cause it'll just snag Server.getLastException() and email it on to me for review
However, I have some TextBoxes on the page and I'd like to send the value of those textboxes along with the email. Maybe it's not quite the DOM I'm looking for access to but instead those posted variables.
I tried looking at HttpContext.Current.Request.Form but it showed no keys.
So Does anyone know how to access the formvalues when globally catching an exception?
Accessing the Form Values
To access the form values in Global.Application_Error, you can simply use HttpContext.Current.Request.Form.
Here is a proof of concept, where a page immediately throws an exception on post(back) to hit the application error handler:
void Application_Error(object sender, EventArgs e)
{
var test = HttpContext.Current.Request.Form;
}
Setting a breakpoint on the assignment to test, then stepping over it (with F10) when it is hit, you can see that test is indeed set to the post(back)'s form-values collection.
Accessing the Postback Control Values
Alternatively, you can access the postback control values by adding them to the session on postback, for example...
// ************code behind
protected void TextBox1_TextChanged(object sender, EventArgs e)
{
Session["TextBox1"] = TextBox1.Text;
}
..., and accessing the session in the application error handler - for instance:
// ************Global.asax.cs
protected void Application_Error(object sender, EventArgs e)
{
// Use Session["TextBox1"].
}
A CodeVerge thread speaks to approach well - particularly Benson Yu's reply.
I don't understand why or what I'm doing wrong, but I get a null reference exception when the follow code is executed in my Windows Phone 8.1 application:
First, the application navigates and passes the selectedStation to the next page...
Code from the MainPage:
// When an item is selected, go to the next page and pass info
private void listBoxStations_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
// Get the selected station item
CompleteStation selectedStation = (CompleteStation)this.listBoxStations.SelectedItem;
this.Frame.Navigate(typeof(StationInformationPage), selectedStation);
// Make sure we set the selected index to -1 after item is selected so
// when we come back to page, no items are selected
this.listBoxStations.SelectedIndex = -1;
}
Here is the code that is getting the null error in the next page:
private CompleteStation station;
protected override void OnNavigatedTo(NavigationEventArgs e)
{
this.navigationHelper.OnNavigatedTo(e);
this.station = (CompleteStation)e.Parameter;
AddInformation();
}
private void AddInformation()
{
this.txtStationTitle.Text = station.StationName;
// Add more information here
}
The error is specifically happening when I try to change the txtStationTile.Text to station.StationName.
If I take out the code that changes the textbox, and I step through the program, it shows that the station variable is not actually null by the end of the OnNavigatedTo method...
Any help would be greatly appreciated!
-Johan
It seems that it's not the station that's null, but the this.txtStationTitle.
You're doing everything in OnNavigatedTo while the page (XAML) including the TextBlock you're trying to change is not completely loaded, so the TextBlock is null and when you try to do this.txtStationTitle.Text, you get a NullReferenceException.
However, if you called AddInformation in Loaded event handler of the Page, then you'd be sure that the page is fully loaded and TextBlock would not be null anymore.
public SomePage()
{
this.InitializeComponent();
this.Loaded += SomePage_Loaded;
}
void SomePage_Loaded(object sender, RoutedEventArgs e)
{
AddInformation();
}
This type of exception is usually very easy to debug. Putting a breakpoint on the following line:
this.txtStationTitle.Text = station.StationName;
and examining this.txtStationTitle and station would make it really simple to find out what exactly is null.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Response.Redirect causes System.Threading.ThreadAbortException
ASP/C#.NET (web forms, not MVC)
UPDATE: Just found a related post (likely rendering this a duplicate): Why Response.Redirect causes System.Threading.ThreadAbortException?
~ ~ ~
After a good bit of research, I have come to the understanding that, in general, when using Response.Redirect(), it is better to pass FALSE for the second parameter, to avoid System.Threading.ThreadAbortException. (http://blogs.msdn.com/b/tmarq/archive/2009/06/25/correct-use-of-system-web-httpresponse-redirect.aspx)
My question is, "Is there a recommended way (pattern) for managing (namely skipping) processing in page events that fire after the redirect, when false is passed for the second parameter?"
This is mostly a problem for me when I am checking for and redirecting on an expired session in Page_Load(). It seems very tedious to have to perhaps set a "_Redirected" flag every time I redirect and then check that flag at the top of every event. I haven't had to worry about this in the past because I always passed TRUE for the second parameter, not knowing any better.
Below is some code showing what I don't want to have to do (check _Redirected before processing each event). Perhaps what I'm looking for is a better Session Expiration Processing pattern.
Any suggestions on how to improve this processing, would be greatly appreciated.
private bool _Redirected = false;
protected void Page_Load(object sender, EventArgs e)
{
if (Session["key"] == null)
{
Response.Redirect("SessionExpired.aspx", false);
Context.ApplicationInstance.CompleteRequest();
_Redirected = true;
}
}
protected void Page_PreRender(object sender, EventArgs e)
{
if (!_Redirected)
{
// do Page_PreRender() stuff...
}
}
protected void Button1_Click(object sender, EventArgs e)
{
if (!_Redirected)
{
// do Button1_Click() stuff...
Response.Redirect("Button1Page.aspx", false);
Context.ApplicationInstance.CompleteRequest();
_Redirected = true;
}
}
protected void Button2_Click(object sender, EventArgs e)
{
if (!_Redirected)
{
// do Button2_Click() stuff...
Response.Redirect("Button2Page.aspx", false);
Context.ApplicationInstance.CompleteRequest();
_Redirected = true;
}
}
~ ~ ~
[01/24/2013] In response to https://stackoverflow.com/users/2424/chris-lively (thank you, btw), here is simplified code that I believe is similar to what you tested. I am still seeing Button1_Click() execute on post back after the Response.Redirect(url, false) with .CompleteRequest() in Page_Load().
protected void Page_Load(object sender, EventArgs e)
{
if (this.IsPostBack)
{
Response.Redirect("Redirect.aspx", false);
Context.ApplicationInstance.CompleteRequest();
}
}
protected void Button1_Click(object sender, EventArgs e)
{
Response.Write("Button1 clicked!");
}
This behavior is corroborated by this response https://stackoverflow.com/a/12957854/1530187 to the similar post I noted above in my update.
Any idea what I'm doing wrong that would cause the page to continue executing after redirect?
You referenced a pretty good article, but your code doesn't reflect what the author suggested as a way to do this "correctly". Namely:
protected void Page_Load(object sender, EventArgs e)
{
if (Session["key"] == null)
{
Response.Redirect("SessionExpired.aspx", false);
Context.ApplicationInstance.CompleteRequest();
}
}
UPDATE
I put together a very simple sample application. All it had was two form pages.
The first page had a button on it that did a response.write. I put a breakpoint on this line. In the page_load method I put a redirect followed immediately by a call to CompleteRequest. This redirect occured was set to occur if the page was posting back.
All the second page did was emit "hello"
I then ran the application, which pulled up the first form. I clicked the button. The break point was never hit and it redirected. This was exactly what I expected it to do. Namely, the page_load method caught the postback, performed a redirect and completed the request immediately without further processing of the page.
This means that there is absolutely no reason to put the if (!_Redirected) code in each of your button clicks. All you need to do is copy/ paste the code I have at the top of this answer. It will prevent those clicks from being called.
I am new to c# and its concepts, so i am sorry if this question is kind of dumb.
I try to do some automatation using the winforms webbrowser control
elements = webBrowser1.Document.GetElementsByTagName("input");
foreach (HtmlElement element in elements)
{
if (element.GetAttribute("value") == "Anzeigen")
element.InvokeMember("click");
}
while (webBrowser1.ReadyState != WebBrowserReadyState.Complete) Application.DoEvents();
// do some math on recived html
// ......
// show results
MessageBox.Show(numPlanets.ToString() );
So, to explain it:
Im looking for a Button with the value "Anzeigen", simulate a click on it, then wait till NEW page is loaded and do my calculations then.
Unfortunately my calculations are done on the OLD HTML content, because its not waiting for the page to load. Strangely if i enter an Thread.Sleep(5000); after the foreach loop, this Sleep is executed BEFORE the click is simulated, and the calculation fails also.
I just need some synchronous behavior for that click, withouth using an event.
Hope u can help me with that, sorry for my bad english
EDIT:
Solved it like this:
Variable bool webbbrowserfinished = false inside the class, if i want synchronous behavior, i do it like this:
webbrowserfinished = false;
// do navigation here
while (!webbrowserfinished)
{
Application.DoEvents();
Thread.Sleep(100);
}
webbrowserfinished = false;
You can try WebBrowser.DocumentCompleted Event
Occurs when the WebBrowser control finishes loading a document.
private void Form1_Load(object sender, EventArgs e)
{
webBrowser1.Navigate("google.com");
webBrowser1.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(webBrowser1_DocumentCompleted);
}
void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
MessageBox.Show("Completed Now!");
}
Well it isn't the best of solutions but you could always start a timer when the web browser navigates, and set timer1.Tick to something like 3000, then within the timer1_Tick method you can do your calculations on the new page, and then timer1.Stop();.
There is probably a better solution using events but I'm not too good with web browsers myself.
You can use Thread.sleep(5000) to wait for your page to load, because if you don't, the navigate method will load a new doc into web browser control but it will not call document_complete_event_handler
is there a way to know that the WebBrowser control has finished loading the page?
currently i am using WebBrowser.ReadyState == WebBrowserReadyState.Complete.
but this indicates that the webpage content is downloaded but sometimes the flash is not loaded yet.
A Flash file loading doesn't report its progress on that back to the browser so unfortunately you can't catch that.
well the best thing i have found is to use a timer to wait for a specifique time like 30 seconds and then the page should be loaded.
not perfect but the best i have thought of.
If you have control over the Flash, you can put an ActionScript event that will then get passed to the browser.
The WebBrowser control has a DocumentCompleted event which you can catch and react on. I don't know if that includes the Flash content loading - the docs aren't very clear on that....
webBrowser1.DocumentCompleted +=
new WebBrowserDocumentCompletedEventHandler(webBrowser1_DocumentCompleted);
private void webBrowser1_DocumentCompleted(object sender,
WebBrowserDocumentCompletedEventArgs e)
{
// do whatever you need to do when the document is completely loaded here
}
You can try this way:
bool loadingPage = true;
private void Browser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
if (this.ReadyState != WebBrowserReadyState.Complete) return;
if ((e.Url.AbsolutePath == "blank") || (e.Url != this.Url)) return;
if (this.Document.Body.All.Count < 20) return;
loadingPage = false
}
private void WaitPageLoad()
{
//To avoid waiting forever. You can add timer here.
while(loadingPage)
{
}
}