webbrowser control just stops - c#

lock (lockVar)
{
if (done)
return;
if (linksvisited.Contains(webBrowser1.Url.OriginalString))
return;
System.Console.WriteLine("Locked: " + webBrowser1.Url.OriginalString);
linksvisited.Add(webBrowser1.Url.OriginalString);
}
webBrowser1.Navigate(nextLink, null, null, "User-Agent: Googlebot/2.1 (+http://www.google.com/bot.html)");
I am using the following code to iterate through a page, but sometimes the webbrowser control will just stop and it won't go to the next page. No exceptions no anything it will just stop, but there is definitely another link it can visit. I am thinking it has something to do with an internal error in the control, but how the heck to I trap it. None of my exception handler catch anything. Nothing in the output console. I have disabled scripting errors.

Where is that code-snippet located? If you have it in an event-handler of the control - it is extremely possible that you are dead-locking yourself. As the Web Browser control can (and will fire) multiple events during the various stages of page load.
The document complete will fire for every frame on the page. (Stack OverFlow)
It is also difficult to comment on an incomplete section of code. I would read (Locking) to understand the intrinsics before continuing too much further. Good luck with your current endeavor.

Related

Winform has Red X exception

I am using a 3rd party control (ComponentOne) and at intermittently I would get this typical red X box such as this typical image shows. At first I thought I have a GDI leak, so after doing some leg works I verified my GDI numbers are fine when drawing controls.
After Googling around I found that this kind of error happens on the OnPaint() event and therefore even if i put a try and catch when calling the control to Render, it wont catch it.
So my next step is to have the following override in my code.
protected override void OnPaint(PaintEventArgs e)
{
try
{
base.OnPaint(e);
}
catch (Exception ex)
{
this.Invalidate(); //attempt to redraw the control
XmSam.Log(ex);
}
}
I think that should do the trick but I can't recreate this problem all the time and so I haven't been able to fully test the above code yet. My question is, if I render my control and it has exception then this code will attempt to redraw the control. Will this stuck in an indefinite loop and freezes my UI? or would you think whatever caused the exception will go away and upon the second control redraw and it should render fine?
I think that should do the trick
No, you made it far worse. Now your OnPaint() method is running over and over again, probably falling over on the same exception repeatedly. You'll see your program burning 100% core as well.
Getting an exception in OnPaint() is not something you can really survive. There's nothing to look at for the user, that's a guaranteed support call. Instead of hiding the problem, use the exception to figure out what actually went wrong and fix the problem. Use Debug + Exceptions, tick the Thrown checkbox for CLR exceptions so the debugger will stop when the exception is raised. Just in case, it is not unlikely that the exception is raised in framework code, also use Tools + Options, Debugging and untick the "Enable Just My Code" option.
When I have seen this in the past it always had to do with a threading issue. Are you updating this control from a different thread than the UI thread?
Its been a while since I've dealt with that but I think the easiest thing to do is use the BackGroundWorker Class to perform background operations and update form controls.
BackGroundWorker Class

How long am I supposed to wait to do something after I call WebBrowser.Refresh?

I have a web page that I am tearing elements out of for use in a program I am writing. It takes a moment for a particular element to load into the web page, so I thought I would use WebBrowser.Refresh() in order to accomplish getting the up to date code.
Unfortunately doing so causes a whole lot of headache if you want to do ANYTHING afterwards since it doesn't fire the DocumentCompleted event (before anyone asks, it even says that explicitly on the MSDN).
So I need a method to allow the program like 2 seconds of doing nothing after it refreshes the page. The problem is that I don't know how to do that and be able to get the updated WebBrowser.Document. If I use Thread.Sleep, the entire application hangs while it sleeps and nothing gets updated.
And if I immediately try, I invariable get the crappy crappy problem of the WebBrowser object hanging forever or throwing Null Cast exceptions.
Has anyone else had this sort of problem (or something similar) and found a solution?
Why don't you just navigate to the URL again?
webBrowser1.Navigate(webBrowser1.Url);
This will fire the event handlers that you need.
I had a similar problem in getting a WebBrowser to refresh at a desired time. As you are discovering, it is hopeless to try to get it to refresh on demand; the HTTP response and HTML rendering are both non-deterministic.
My advice is to attach to the DocumentCompleted event of the WebBrowser, call the desired web page early in the background and show the user something to distract them, then show the completed WebBrowser after DocumentCompleted fires.
If you want to be lazy and not use background threads:
wb.Refresh();
while ((wb.ReadyState != WebBrowserReadyState.Complete)) {
Application.DoEvents();
}
//Refresh is now complete
ReadyState should only be WebBrowserReadyState.Complete once all Ajax and content has completed loading.

Problem with Application.DoEvents() while waiting for WebBrowser to finish loading

I'm trying to load WebBrowser content and after that I want to add some text and scroll to the bottom.
Here's example of my code:
webBrowser1.Url = new System.Uri("file:///" + filePath);
webBrowser1.Document.Body.InnerHtml += text;
webBrowser1.Document.Body.ScrollTop = webBrowser1.Document.Body.ScrollRectangle.Height;
When I run it, there's an unhandled exception "Object reference not set to an instance of an object". Or when I comment line that does the scrolling, then text is added to previous content of the WebBrowser and then navigating to new content.
So after 1st line of my example code I put:
while (webBrowser1.ReadyState != WebBrowserReadyState.Complete) Application.DoEvents();
but it messes up everything. My application is doing really strange things, for example calling the same method many times, when it should be called once.
Is there any solution?
I think you actually want to subscribe to DocumentCompleted event.
Application.DoEvents only processes pending Windows message loop items.
In either case, make sure you understand possible drawbacks of calling DoEvents before using it at all.
DoEvents() is a bad solution here. You should use explicit thread or BackgroundWorker to load pages and leave UI thread to handle other stuff.

AxAcroPDF swallowing keys, how to get it to stop?

The AxAcroPDF swallows all key-related events as soon as it gets focus, including shortcuts, key presses, etc. I added a message filter, and it doesn't get any key-related messages either. It's a COM component, could that be relevant?
Is there any way to catch these before the control starts swallowing them?
Hans is correct, the Acrobat Reader spawns two child AcroRd32 processes which you have no direct access to from within your managed code.
I have experimented with this and you have three viable options:
You can create a global system hook, and then look for and filter out / respond to WM_SETFOCUS messages sent to your child AcroRd32 windows. You can accomplish some of this from within C# by using a wrapper library, such as the one here: http://www.codeproject.com/KB/system/WilsonSystemGlobalHooks.aspx
You also need to identify the correct processes as there may be more than one instance of your application, or other instances of AcroRd32. This is the most deterministic solution, but because your application will now be filtering messages sent to every single window in existence, I generally don't recommend this approach because then your program could negatively affect system stability.
Find an alternate PDF viewing control. See this answer for a few commercial components: .net PDF Viewer control , or roll your own: http://www.codeproject.com/KB/applications/PDFViewerControl.aspx
Find an acceptable hack. Depending on how robust your application needs to be, code such as the following may be suitable (it was suitable for my case):
DateTime _lastRenav = DateTime.MinValue;
public Form1()
{
InitializeComponent();
listBox1.LostFocus += new EventHandler(listBox1_LostFocus);
}
private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
{
axAcroPDF1.src = "sample.pdf"; //this will cause adobe to take away the focus
_lastRenav = DateTime.Now;
}
void listBox1_LostFocus(object sender, EventArgs e)
{
//restores focus if it were the result of a listbox navigation
if ((DateTime.Now - _lastRenav).TotalSeconds < 1)
listBox1.Focus();
}
I might finally have a ridiculously simple answer. So far in testing this is working.
Having suffered from this problem for quite some time and having built a complex system of each custom control recording which of them last had focus and using a timer to flip focus back (when acropdf grabbed it) I revisited this problem and read a great number of answers (looking for recent solutions). The information gleaned helped me with the idea.
The idea is to disable the (acropdf) control whilst it is loading as in the following example (code reduced for clarity)
AxAcroPDF_this.Enabled = False
AxAcroPDF_this.src = m_src
Then on a timer, after say 1 second.
AxAcroPDF_this.Enabled = True
Basically the idea is to tell Windows not to let users use the acropdf control until allowed, so asking Windows to prevent it from getting focus (because users are not allowed in there).
So far this is holding up, I will edit this if anything changes. If it doesn't work completely for you then maybe the idea points into a useful direction.
It is an out-of-process COM component, that's the problem. Completely in violation of Windows SDK requirements as laid out in SetParent(). Once its window gets the focus, the message loop in the acroread.exe process gets all the messages, your message filter cannot see any messages anymore.
Technically it is fixable by using SetWindowsHookEx() to inject a DLL into the process and monitor messages with WH_GETMESSAGE. But you can't write such a DLL in the C# language.
Major suck, I know. There never seems to be any lack of it with that program.
For some reason Tim's answer, disabling the AxAcroPDF control directly, didn't work in my case. The Leave event on the previously-selected Textbox would never fire, either.
What is working is nesting the AxAcroPDF control inside of a disabled GroupBox. Since the users of my application need to only see the PDF, not interact with it, the GroupBox's Enabled property is set to False in the designer.

ASP.Net's auto-postback. What happens when its too slow?

I am making a web application. I have gotten a weird error with update panels.
Ok, so say you have two update panels and each update panel has a textbox in it. Both of these textboxes are auto-postback and the update panels update conditionally.
Well, from the behavior I'm observing it seems like if the server isn't faster than the user at processing a request then it sorta gets ignored on the client side.
Like say you type something in 1 of these text boxes and then quickly tab to the next one and type something and tab out. This should cause 2 post backs.
Well, what if 1 post back is being processed at the server and another one happens? Does that post back get dropped at the server side or client side?
The main problem I'm observing with this situation is that when a post back occurs the 1st time, there is a Update() for an update panel. Well, when the 2nd post back occurs interrupting the first, it also does an Update on an update panel(a different one). What the user sees is if they tab through it very quickly(or the server is under high load or whatever) then the 2nd update panel gets updated but not the first.
tl;dr: When a post back interrupts another post back, any update panels that were suppose to be updated in the first post back are not updated(though the second postback ones are)
How can I work around this problem or solve it? I can not update all of the update panels on the screen because then the control that the user is currently on loses focus along with a whole lot of other problems.
UpdatePanels intercept the postback and make a request back to the server using the XMLHTTPRequest object (i.e. they use AJAX).
The second XMLHTTPRequest will cancel the first one if it is still in progress when the second one is made. This is standard behaviour as far as I am aware.
You might want to have the UpdatePanels update together on a button click as opposed to having the update attached to an event on each textbox (it sounds like you have them attached to the blur event). This way you can ensure that lots of requests aren't being made and perhaps disable the button whilst a request is in progress, to prevent a new request from cancelling the one in progress.
EDIT:
You can prevent another request being made form the client side while one request is already in progress by checking the PageRequestManager's isInAsyncPostBack property. Something like the following
function pageLoad(sender, args) {
var pageManager = Sys.WebForms.PageRequestManager.getInstance();
// add a function to execute when an asynchronous postback is initialized
pageManager.add_initializeRequest(checkAsyncPostback);
}
function checkAsyncPostback(sender, arg)
{
var pageManager = Sys.WebForms.PageRequestManager.getInstance();
// check if an async postback is already in progress
if (pageManager.get_isInAsyncPostBack()) {
// cancel this async postback if one is currently in progress
arg.set_cancel(true);
}
}
There isn't really an easy way to know from the server side if the postback is interrupted.
I can't answer your questions specifically, because I don't know how the page manages UpdatePanels and their requests/responses. But, you can probably very easily tell what's going on if you trace the calls with Fiddler. You can see when the requests are firing, and you can see the response as well as if an HTTP error code is sent back or an exception is thrown, etc:
Fiddler2
Look at using the UpdateProgress control: http://www.asp.net/ajax/documentation/live/overview/UpdateProgressOverview.aspx
Also, UpdatePanels are overkill for this kind of thing. Look at using Page Methods (google ASP.NET Page Methods)
EDIT: To further clarify how this would be useful to you, modify the contents of the ProgressTemplate in the UpdateProgress control to display in a modal fashion, so that users cannot do anything until the request completes.

Categories

Resources