Why is the Url value in C# WebBrowser always null? - c#

I am trying to load a local HTML file into an instance of C# WebBrowser (WinForms).
This is what I am doing:
string url = #"file:///C:MyHtml/hello.html";
myWebbrowser.Url = new Uri(url, UriKind.Absolute);
object test = myWebbrowser.Url; // breakpoint here
The path above is correct; if I copy it and paste into an external browser, the file is immediately opened. But the instance of WebBrowser does not want to react. I set a breakpoint in the last line of the snippet, and what I get there is that myWebbrowser.Url is null (the test variable). The control remains correspondingly empty.
myWebbrowser.AllowNavigation is explicitly set to true. I have also tried all possible versions of slashes and backslashes; the result is always the same. The version of the webbrowser seems to be 11 (myWebbrowser.Version = "{11.0.18362.1139}"). I am working in Windows 10, VS 2019.
What can be wrong in this setup?

The path above is correct; if I copy it and paste into an external browser, the file is immediately opened. But the instance of WebBrowser does not want to react. I set a breakpoint in the last line of the snippet, and what I get there is that myWebbrowser.Url is null.
I was able to replicate this exact issue, it's because the property of the Url doesn't get actually set until the document has actually finished loading.
To resolve this issue, you must handle the DocumentCompleted event. You can do so for example:
string url = #"file:///C:MyHtml/hello.html";
myWebbrowser.DocumentCompleted += MyWebbrowser_DocumentCompleted;
myWebbrowser.Url = new Uri(url, UriKind.Absolute);
Create a new routine to handle the DocumentCompleted event:
private void MyWebbrowser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
string test = myWebbrowser.Url.ToString();
}
You can also get the Url from the WebBrowserDocumentCompletedEventArgs:
string testUrl = e.Url.ToString();
I am not sure exactly why when setting the Url and then checking it, it is null, I haven't found anything to explain why. My only guess is that it may be an invalid Url and or path, if navigation succeeds then that property is set.
Edit: upon looking at the source for WebBrowserDocumentCompleted, it does seem the Url property is only set in the DocumentCompleted, you can see more there.
Please note: you must register the DocumentCompleted event first before setting the Url property as when you do, it will navigate first and you will not receive the DocumentCompleted event.

I was able to find out why it did not want to function, at least I hope so. The "hello.html" file contained calls to jquery and THREE.js, while WebBroser seems not to support the latter. Therefore I did not see any content in the control. After I threw out THREE.js and inserted most simple HTML code, it worked just OK! Now I am busy trying to bring WebBrowser to support THREE.js (there exists a skeptical opinion about this, though).

Related

C# - GeckoFX vs InnerHTML

If I would use default Visualstudio webBrowser control (IE) i would just write something like this:
textBox3.Text = webBrowser1.Document.GetElementById("mydivid").InnerHtml;
But I'm stubborn to use GeckoFX (Mozilla) and ofcourse it doesn't work. What I found is information that I need to adress "HTMLDocument" not "Document" to pull my desired value. But no example that fit my needs.
How to get this innerHTML of this particular element?
--- Response to #Timothy Groote ---
I've read the other topic - there's no example of code with GetElementById, it's like wide definition, but I need specific one - I cannot read this codeand get clear information what method or property shoueld I use in my app.
I can add that my element is and will be always HTML element, so i don't need to verify that every time with "if".
When I use "the other code" in my app result (instead of innerHTML) was only:
<head></head><body></body>
In "the other code" has also a mistake:
var geckoDomElement = WebBrowser1.Document.DocumentElement;
There's no webBrowser1 control! Only geckoWebBrowser1, neither works!
--- Edit2 ---
I was also thinking about something like that:
textBox3.text = (GeckoHtmlElement)geckoWebBrowser1.Document.GetElementById("mydivid")....
but there's also no "innerHtml"
in
(GeckoHtmlElement)geckoWebBrowser1.Document.DocumentElement
there's no "getElementById".
If you using Geckofx 45 then its very simple , just try like this....
GeckoHtmlElement testelement = null;
testelement = (GeckoHtmlElement)webBrowser1.Document.GetElementById("test");
string text=testelement .InnerHtml;
if you don't know how to use Geckofx 45 then try this simple tutorial ..
How to use or embed Geckofx 45 Webbrowser control into Visual Studio into WinForms Applications
ANSWER
Of course defining variable:
GeckoHtmlElement machcode;
Finding element:
machcode = geckoWebBrowser1.Document.GetHtmlElementById("machinecode");
And finally reading the content:
textBox3.Text = machcode.InnerHtml;
And one important thing was to place code in DocumentComplete event!
Every solutions provided in web were wrong - some point into nonexisting webBrowser1 control, some forget about definition, some throw null exception, some use wrong GetElement instead of GetHtmlElement.

Selenium chrome driver click() method not always clicking on elements

I am writing integration tests in c# and when I use the click() method on certain elements inside a dialog box nothing happens and I get no errors. It will click some of the elements inside the dialog but not others. I thought if it wasn't selecting them properly then it would throw and exception but it runs smooth and says test passed even though it never actually clicked the button. The dialog box is an iframe.
I thought maybe it was trying to click a button that wasn't display yet or enabled so I added this before the click() call:
_driver.SwitchTo().Frame(_frameElement);
_wait.Until(d =>
{
var shippingInfoButton = d.FindElement(By.CssSelector("input[title ='Info']"));
return shippingInfoButton.Displayed && shippingInfoButton.Enabled;
});
var infoButton = _driver.FindElement(By.CssSelector("input[title ='Info']"));
ScrollToElement(infoButton);
infoButton.Click();
again this runs with no thrown exceptions so I'm assuming it has found the element and it is both displayed and enabled.
Let me know if you need any more info. Thanks
I can't explain why the selenium driver .click() method won't fire on some elements in the page but not others, but I did find a solution.
Using IJavaScriptExecutor you can click the element using javascript instead and in my case it worked.
Here is the code to run the IJavaScriptExecutor and below is my whole method.
//IJavaScriptExecutor
IJavaScriptExecutor js = _driver as IJavaScriptExecutor;
js.ExecuteScript("arguments[0].click();", infoButton);
//my whole method for clicking the button and returning the page object
public ShippingMethodDetailsPageObject SelectShippingMethodInfo()
{
_driver.SwitchTo().Frame(_frameElement);
_wait.Until(d =>
{
var shippingInfoButton = d.FindElement(By.CssSelector("input[title='Info']"));
return shippingInfoButton.Displayed && shippingInfoButton.Enabled;
});
var infoButton = _driver.FindElement(By.CssSelector("input[title ='Info']"));
IJavaScriptExecutor js = _driver as IJavaScriptExecutor;
js.ExecuteScript("arguments[0].click();", infoButton);
_driver.SwitchTo().DefaultContent();
return new ShippingMethodDetailsPageObject(_driver, false);
}
I ran into a similar problem. If it's the same problem there's a fault in the ChromeDriver it can't click certain elements because of surrounding divs etc. Bit lame really.
A simple fix is to send the Enter key e.g. element.SendKeys(Keys.Enter). Seems to work across all browsers.
I have some tests that works in Firefox all the times, and in Chrome it drove me mad, because sometimes it passed successfully, and sometimes the ".click" didn't work and it would fail the test.
Took a long time to notice it, but the reason was: I used to sometimes minimize the browser to 80% to be able to see the browser along side my IDE. it appears that the ".click" doesn't work when I did it.
At least for me this was the issue

I must be a heretic for wanting a C# browser with both NewWindow2 and GetElementsByTagName

You can't have your cake and eat it too, apparently.
I'm currently using the System.Windows.Forms.WebBrowser in my application. The program currently depends on using the GetElementsByTagName function. I use it to gather up all the elements of a certain type (either "input"s or "textarea"s), so I can sort through them and return the value of a specific one. This is the code for that function (my WebBrowser is named web1):
// returns the value from a element.
public String FetchValue(String strTagType, String strName)
{
HtmlElementCollection elems;
HtmlDocument page = web1.Document.Window.Frames[1].Document;
elems = page.GetElementsByTagName(strTagType);
foreach (HtmlElement elem in elems)
{
if (elem.GetAttribute("name") == strName ||
elem.GetAttribute("ref") == strName)
{
if (elem.GetAttribute("value") != null)
{
return elem.GetAttribute("value");
}
}
}
return null;
}
(points to note: the webpage I need to pull from is in a frame, and depending on circumstances, the element's identifying name will be either in the name or the ref attribute)
All of that works like a dream with the System.Windows.Forms.WebBrowser.
But what it is unable to do, is redirect the opening of a new window to remain in the application. Anything that opens in a new window shoots to the user's default browser, thus losing the session. This functionality can be easily fixed with the NewWindow2 event, which System.Windows.Forms.WebBrowser doesn't have.
Now forgive me for being stunned at its absence. I have but recently ditched VB6 and moved on to C# (yes VB6, apparently I am employed under a rock), and in VB6, the WebBrowser possessed both the GetElementsByTagName function and the NewWindow2 event.
The AxSHDocVw.WebBrowser has a NewWindow2 event. It would be more than happy to help me route my new windows to where I need them. The code to do this in THAT WebBrowser is (frmNewWindow being a simple form containing only another WebBrowser called web2 (Dock set to Fill)):
private void web1_NewWindow2(
object sender,
AxSHDocVw.DWebBrowserEvents2_NewWindow2Event e)
{
frmNewWindow frmNW = new frmNewWindow();
e.ppDisp = frmNW.web2.Application;
frmNW.web2.RegisterAsBrowser = true;
frmNW.Visible = true;
}
I am unable to produce on my own a way to replicate that function with the underwhelming regular NewWindow event.
I am also unable to figure out how to replicate the FetchValue function I detailed above using the AxSHDocVw.WebBrowser. It appears to go about things in a totally different way and all my knowledge of how to do things is useless.
I know I'm a sick, twisted man for this bizarre fantasy of using these two things in a single application. But can you find it in your heart to help this foolish idealist?
I could no longer rely on the workaround, and had to abandon System.Windows.Forms.WebBrowser. I needed NewWindow2.
I eventually figured out how to accomplish what I needed with the AxWebBrowser. My original post was asking for either a solution for NewWindow2 on the System.Windows.Forms.WebBrowser, or an AxWebBrowser replacement for .GetElementsByTagName. The replacement requires about 4x as much code, but gets the job done. I thought it would be prudent to post my solution, for later Googlers with the same quandary. (also in case there's a better way to have done this)
IHTMLDocument2 webpage = (IHTMLDocument2)webbrowser.Document;
IHTMLFramesCollection2 allframes = webpage.frames;
IHTMLWindow2 targetframe = (IHTMLWindow2)allframes.item("name of target frame");
webpage = (IHTMLDocument2)targetframe.document;
IHTMLElementCollection elements = webpage.all.tags("target tagtype");
foreach (IHTMLElement element in elements)
{
if (elem.getAttribute("name") == strTargetElementName)
{
return element.getAttribute("value");
}
}
The webbrowser.Document is cast into an IHTMLDocument2, then the IHTMLDocument2's frames are put into a IHTMLFramesCollection2, then I cast the specific desired frame into an IHTMLWindow2 (you can choose frame by index # or name), then I cast the frame's .Document member into an IHTMLDocument2 (the originally used one, for convenience sake). From there, the IHTMLDocument2's .all.tags() method is functionally identical to the old WebBrowser.Document.GetElementsByTagName() method, except it requires an IHTMLElementCollection versus an HTMLElementCollection. Then, you can foreach the collection, the individual elements needing to be IHTMLElement, and use .getAttribute to retrieve the attributes. Note that the g is lowercase.
The WebBrowser control can handle the NewWindow event so that new popup windows will be opened in the WebBrowser.
private void webBrowser1_NewWindow(object sender, CancelEventArgs e)
{
// navigate current window to the url
webBrowser1.Navigate(webBrowser1.StatusText);
// cancel the new window opening
e.Cancel = true;
}
http://social.msdn.microsoft.com/Forums/en-US/csharpgeneral/thread/361b6655-3145-4371-b92c-051c223518f2/
The only solution to this I have seen was a good few years ago now, called csExWb2, now on Google code here.
It gives you an ExWebBrowser control, but with full-on access to all the interfaces and events offered by IE. I used it to get deep and dirty control of elements in a winforms-hosted html editor.
It may be a bit of a leap jumping straight into that, mind.

Webbrowser control is not showing Html but shows webpage

I am automating a task using webbrowser control , the site display pages using frames.
My issue is i get to a point , where i can see the webpage loaded properly on the webbrowser control ,but when it gets into the code and i see the html i see nothing.
I have seen other examples here too , but all of those do no return all the browser html.
What i get by using this:
HtmlWindow frame = webBrowser1.Document.Window.Frames[1];
string str = frame.Document.Body.OuterHtml;
Is just :
The main frame tag with attributes like SRC tag etc, is there any way how to handle this?Because as i can see the webpage completely loaded why do i not see the html?AS when i do that on the internet explorer i do see the pages source once loaded why not here?
ADDITIONAL INFO
There are two frames on the page :
i use this to as above:
HtmlWindow frame = webBrowser1.Document.Window.Frames[0];
string str = frame.Document.Body.OuterHtml;
And i get the correct HTMl for the first frame but for the second one i only see:
<FRAMESET frameSpacing=1 border=1 borderColor=#ffffff frameBorder=0 rows=29,*><FRAME title="Edit Search" marginHeight=0 src="http://web2.westlaw.com/result/dctopnavigation.aspx?rs=WLW12.01&ss=CXT&cnt=DOC&fcl=True&cfid=1&method=TNC&service=Search&fn=_top&sskey=CLID_SSSA49266105122&db=AK-CS&fmqv=s&srch=TRUE&origin=Search&vr=2.0&cxt=RL&rlt=CLID_QRYRLT803076105122&query=%22LAND+USE%22&mt=Westlaw&rlti=1&n=1&rp=%2fsearch%2fdefault.wl&rltdb=CLID_DB72585895122&eq=search&scxt=WL&sv=Split" frameBorder=0 name=TopNav marginWidth=0 scrolling=no><FRAME title="Main Document" marginHeight=0 src="http://web2.westlaw.com/result/dccontent.aspx?rs=WLW12.01&ss=CXT&cnt=DOC&fcl=True&cfid=1&method=TNC&service=Search&fn=_top&sskey=CLID_SSSA49266105122&db=AK-CS&fmqv=s&srch=TRUE&origin=Search&vr=2.0&cxt=RL&rlt=CLID_QRYRLT803076105122&query=%22LAND+USE%22&mt=Westlaw&rlti=1&n=1&rp=%2fsearch%2fdefault.wl&rltdb=CLID_DB72585895122&eq=search&scxt=WL&sv=Split" frameBorder=0 borderColor=#ffffff name=content marginWidth=0><NOFRAMES></NOFRAMES></FRAMESET>
UPDATE
The two url of the frames are as follows :
Frame1 whose html i see
http://web2.westlaw.com/nav/NavBar.aspx?RS=WLW12.01&VR=2.0&SV=Split&FN=_top&MT=Westlaw&MST=
Frame2 whose html i do not see:
http://web2.westlaw.com/result/result.aspx?RP=/Search/default.wl&action=Search&CFID=1&DB=AK%2DCS&EQ=search&fmqv=s&Method=TNC&origin=Search&Query=%22LAND+USE%22&RLT=CLID%5FQRYRLT302424536122&RLTDB=CLID%5FDB6558157526122&Service=Search&SRCH=TRUE&SSKey=CLID%5FSSSA648523536122&RS=WLW12.01&VR=2.0&SV=Split&FN=_top&MT=Westlaw&MST=
And the properties of the second frame whose html i do not get are in the picture below:
Thank you
I paid for the solution of the question above and it works 100 %.
What i did was use this function below and it returned me the count to the tag i was seeking which i could not find :S.. Use this to call the function listed below:
FillFrame(webBrowser1.Document.Window.Frames);
private void FillFrame(HtmlWindowCollection hwc)
{
if (hwc == null) return;
foreach (HtmlWindow hw in hwc)
{
HtmlElement getSpanid = hw.Document.GetElementById("mDisplayCiteList_ctl00_mResultCountLabel");
if (getSpanid != null)
{
doccount = getSpanid.InnerText.Replace("Documents", "").Replace("Document", "").Trim();
break;
}
if (hw.Frames.Count > 0) FillFrame(hw.Frames);
}
}
Hope it helps people .
Thank you
For taking html you have to do it that way:
WebClient client = new WebClient();
string html = client.DownloadString(#"http://stackoverflow.com");
That's an example of course, you can change the address.
By the way, you need using System.Net;
This works just fine...gets BODY element with all inner elements:
Somewhere in your Form code:
wb.Url = new Uri("http://stackoverflow.com");
wb.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(wbDocumentCompleted);
And here is wbDocumentCompleted:
void wb1DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
var yourBodyHtml = wb.Document.Body.OuterHtml;
}
wb is System.Windows.Forms.WebBrowser
UPDATE:
The same as for the document, I think that your second frame is not loaded at the time you check for it's content...You can try solutions from this link. You will have to wait for your frames to be loaded in order to see its content.
The most likely reason is that frame index 0 has the same domain name as the main/parent page, while the frame index 1 has a different domain name. Am I correct?
This creates a cross-frame security issue, and the WB control just leaves you high and dry and doesn't tell you what on earth went wrong, and just leaves your objects, properties and data empty (will say "No Variables" in the watch window when you try to expand the object).
The only thing you can access in this situation is pretty much the URL and iFrame properties, but nothing inside the iFrame.
Of course, there are ways to overcome teh cross-frame security issues - but they are not built into the WebBrowser control, and they are external solutions, depending on which WB control you are using (as in, .NET version or pre .NET version).
Let me know if I have correctly identified your problem, and if so, if you would like me to tell you about the solution tailored to your setup & instance of the WB control.
UPDATE: I have noticed that you're doing a .getElementByTagName("HTML")(0).outerHTML to get the HTML, all you need to do is call this on the document object, or the .body object and that should do it. MyDoc.Body.innerHTML should get the the content you want. Also, notice that there are additional iFrames inside these documents, in case that is of relevance. Can you give us the main document URL that has these two URL's in it so we / I can replicate what you're doing here? Also, not sure why you are using DomElement but you should just cast it to the native object it wants to be cast to, either a IHTMLDocument2 or the object you see in the watch window, which I think is IHTMLFrameElement (if i recall correctly, but you will know what i mean once you see it). If you are trying to use an XML object, this could be the reason why you aren't able to get the HTML content, change the object declaration and casting if there is one, and give it a go & let us know :). Now I'm curious too :).

Problem using WebBrowser control as editor

I am currently working on a project where I am using a WebBrowser control as an editor. I have design mode turned on and it seems to be working. The issue im having is when I try to save the Document and load another it pops up the "This document has been modified." message. What I am trying to do is as simple as this
if (frontPage)
{
frontPage = false;
frontContent = webEditor.DocumentText;
webEditor.DocumentText = backContent;
}
else
{
frontPage = true;
backContent = webEditor.DocumentText;
webEditor.DocumentText = frontContent;
}
Like I said everytime I enter some text and run this code it just pops up a message saying its been modified and asks if I want to save. How can I get around this?
You should create the following function:
void ChangeAllowWebBrowserDrop() { webBrowser.AllowWebBrowserDrop = !webBrowser.AllowWebBrowserDrop; }
It should be called every time before you change DocumentText.
You could set
BodyHtml.
Like this:
string newHTMLString="some html";
webBrowser1.Document.Body.InnerHtml = newHTMLString;
Worked for me .
You should create the following function:
void ChangeAllowWebBrowserDrop() {
webBrowser.AllowWebBrowserDrop = !webBrowser.AllowWebBrowserDrop;
}
It should be called every time before you change DocumentText.
better solution is to write empty string before you actually assign your html code:
WebBrowser1.Document.Write(string.Empty);
WebBrowser1.DocumentText = "your code";
I have solved this problem so:
browser.Document.Write(string.Empty);
browser.DocumentText="Your html code";
This is from this link:
http://social.msdn.microsoft.com/Forums/vstudio/en-US/3a9c1965-8559-4972-95e1-da0e86cf87bb/webbrowser-strange-problem
The way Windows Forms load a document stream (used by the DocumentText property) is to navigate away to about:blank, which triggers the document modified message, then load the stream in its DocumentComplete event handler.
Since you already have a document, you can skip the navigation and load the stream into the existing document directly via its IPersistStreamInit interface like Windows Forms does in its DocumentComplete event handler.
Try this webEditor.ScriptErrorsSuppressed = true;
Make sure you have disabled Script Debugging in IE in case you've turned it on.

Categories