I'm trying to programmatically load a web page via the WebBrowser control with the intent of testing the page & it's JavaScript functions. Basically, I want to compare the HTML & JavaScript run through this control against a known output to ascertain whether there is a problem.
However, I'm having trouble simply creating and navigating the WebBrowser control. The code below is intended to load the HtmlDocument into the WebBrowser.Document property:
WebBrowser wb = new WebBrowser();
wb.AllowNavigation = true;
wb.Navigate("http://www.google.com/");
When examining the web browser's state via Intellisense after Navigate() runs, the WebBrowser.ReadyState is 'Uninitialized', WebBrowser.Document = null, and it overall appears completely unaffected by my call.
On a contextual note, I'm running this control outside of a Windows form object: I do not need to load a window or actually look at the page. Requirements dictate the need to simply execute the page's JavaScript and examine the resultant HTML.
Any suggestions are greatly appreciated, thanks!
You should handle the WebBrowser.DocumentComplete event, once that event is raised you will have the Document etc.
wb.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(wb_DocumentCompleted);
private void wb_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
WebBrowser wb = sender as WebBrowser;
// wb.Document is not null at this point
}
Here is a complete example, that I quickly did in a Windows Forms application and tested.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
WebBrowser wb = new WebBrowser();
wb.AllowNavigation = true;
wb.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(wb_DocumentCompleted);
wb.Navigate("http://www.google.com");
}
private void wb_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
WebBrowser wb = sender as WebBrowser;
// wb.Document is not null at this point
}
}
Edit: Here is a simple version of code that runs a window from a console application. You can of course go further and expose the events to the console code etc.
using System;
using System.Windows;
using System.Windows.Forms;
namespace ConsoleApplication1
{
class Program
{
[STAThread]
static void Main(string[] args)
{
Application.Run(new BrowserWindow());
Console.ReadKey();
}
}
class BrowserWindow : Form
{
public BrowserWindow()
{
ShowInTaskbar = false;
WindowState = FormWindowState.Minimized;
Load += new EventHandler(Window_Load);
}
void Window_Load(object sender, EventArgs e)
{
WebBrowser wb = new WebBrowser();
wb.AllowNavigation = true;
wb.DocumentCompleted += wb_DocumentCompleted;
wb.Navigate("http://www.bing.com");
}
void wb_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
Console.WriteLine("We have Bing");
}
}
}
You probably need to host the control in a parent window. You can do this without breaking requirements by simply not showing the window that hosts the browser control by moving it off screen. It might also be useful for development to "see" that it does actually load something for testing, verification etc.
So try:
// in a form's Load handler:
WebBrowser wb = new WebBrowser();
this.Controls.Add(wb);
wb.AllowNavigation = true;
wb.Navigate("http://www.google.com/");
Also check to see what other properties are set on the WebBrowser object when you instantiate it via the IDE. E.g. create a Form, drop a browser control onto it and then check the form's designer file to see what code is generated. You might be missing some key property that needs to be set. I've discovered many-an-omission in my code in this way and also learned how to properly instantiate visual objects programmatically.
P.S. If you do use a host window, it should only be visible during development. You would hide in some manner for production.
Another approach:
You could go "raw" by tryiing something like this:
System.Net.WebClient wc = new System.Net.WebClient();
System.IO.StreamReader webReader = new System.IO.StreamReader(
wc.OpenRead("http://your_website.com"));
string webPageData = webReader.ReadToEnd();
...then RegEx or parse webPageData for what you need. Or do you need the jscript in the page to actually execute? (Which should be possible with .NET 4.0)
I had this problem, and I did not realize that I had uninstalled Internet Explorer. If you have, nothing will ever happen, since the WebBrowser control only instantiates IE.
The Webbrowser control is just a wrapper around Internet Explorer.
You can set in onto an invisible Windows Forms window to completely instantiate it.
Related
I'm tiring to emulate the google search with gecko web browser. so far i have able to go to the google page and then search some thing like this:
geckoWebBrowser1.Navigate("https://www.google.com/");
await Task.Run(() => CheckDocumentLoaded());
var page = geckoWebBrowser1.Document.GetElementById("lst-ib");
(page as GeckoHtmlElement).Focus();
(page as GeckoInputElement).Value = "something";
now i simply want to click on the search button. so i added this to the first part:
var button = new GeckoButtonElement(geckoWebBrowser1.Document.GetElementById("mKlEF").DomObject);
button.Click();
but funny things happens. if i run this code after the first part nothing will happens. but if i created a button and put the code on it it works just fine.
private void Button1_Click(object sender, EventArgs e)
{
var button = new GeckoButtonElement(geckoWebBrowser1.Document.GetElementById("mKlEF").DomObject);
button.Click();
return;
}
but i have to click on button manually in order to make it work. its really confusing. i have no idea what causes this!!
NOTE:
you have to use this user agent if you want to the code works: (Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko)
i don't want to use the SendKeys.Send("{ENTER}").
if i press the button programmatically its not work either.
I played around and recreated your scenario in a WPF app.
I got it working using the DocumentCompleted event that
occurs after the browser has finished parsing a new page and updated the Document property.
I subscribe to the event listener before navigation and remove it once the handler is invoked.
Then, I call the first element of the form to submit the search.
(_browser.Document.GetElementsByTagName("form").First() as GeckoFormElement).submit();
Full code sample: WPF app
using Gecko;
using Gecko.DOM;
using System.Windows;
using System.Windows.Forms.Integration;
using System.Linq;
namespace GeckoWpf {
public partial class MainWindow : Window {
public MainWindow() {
InitializeComponent();
Gecko.Xpcom.Initialize("Firefox");
}
void browser_DocumentCompleted(object sender, System.EventArgs e) {
//unsubscribe
_browser.DocumentCompleted -= browser_DocumentCompleted;
XPathResult xpathResult = _browser.Document.EvaluateXPath("//div/input");
var foundNodes = xpathResult.GetNodes();
foreach (var node in foundNodes) {
GeckoInputElement txtbox = new GeckoInputElement(node.DomObject);
txtbox.Value = "Mona Lisa"; //add the search term
}
(_browser.Document.GetElementsByTagName("form").First() as GeckoFormElement).submit();
}
WindowsFormsHost _host = new WindowsFormsHost();
GeckoWebBrowser _browser = new GeckoWebBrowser();
private void Window_Loaded(object sender, RoutedEventArgs e) {
_browser.DocumentCompleted += browser_DocumentCompleted;
_host.Child = _browser; GridWeb.Children.Add(_host);
_browser.Navigate("https://www.google.com/");
}
}
}
Note: This approach may not work on all pages since DocumentComplete may get fired multiple times for various reasons (e.g. i/frames, AJAX and other dynamic stuff).
PS: Nonetheless, your endeavor may or may not be legal.
You may want to consider using Google's custom search API or alternatives like SerpApi instead.
To print document I have created separate WindowsApplication and each time I want to print any document I call that application with path as parameter and Print application have below code:
public static void Print(string path)
{
WebBrowser wb = new WebBrowser();
wb.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(webBrowser_DocumentCompleted);
wb.Navigate(path);
}
public static void webBrowser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
WebBrowser wb = (WebBrowser)sender;
if (wb.ReadyState.Equals(WebBrowserReadyState.Complete))
{
((SHDocVw.WebBrowser)wb.ActiveXInstance).PrintTemplateTeardown += Print_PrintTemplateTeardown;
wb.ShowPrintDialog();
}
}
void Print_PrintTemplateTeardown(object pDisp)
{
_Application.Exit();
}
When I call Print aaplication, using "WebBrowser" control it loads document and show Print Dialog using "wb.ShowPrintDialog();".
On Print Dialog when I click Print or Cancel I got PrintTemplateTeardown event where I asks Application to Exit (To close application).
Now I want to remove "SHDocVw" dependency from my Print Application due to some security issue while installing on client's machine through Internet.
If I remove "SHDocVw", is there any alternate event or solution available that achknowledge me that PrintDialog is closed?
I am new to windows Phone development, so please excuse my ignorance.
I need to create and open a WebBrowser on a button click (button created on xaml page) in C# code. I have seen so many examples where the WebBrowser is created in XAML and Navigate is called in C#. But my requirement is to create a complete screen on button click.
Can anyone help me with this ? Any level of guidance would be helpful.
From the top of my head and assuming the main grid is named "LayoutRoot":
private void btnOpenAndGo_Click(object sender, RoutedEventArgs e)
{
WebBrowser web = new WebBrowser();
web.Height = LayoutRoot.Height;
web.Width = LayoutRoot.Width;
LayoutRoot.Children.Add(web);
web.Navigate(...);
}
Edit: To control the hardware back button. Override OnBackKeyPress. And do something like this:
protected override void OnBackKeyPress(CancelEventArgs e)
{
base.OnBackKeyPress(e);
if (web.Visibility = Visibility.Visibile)
{
web.Visibility = Visibility.Collapsed;
e.Cancel = true;
}
}
JonPall's Answer is nice, and if you want to open you uri in IE, try this method:
using namespace : Microsoft.Phone.Tasks
WebBrowserTask task = new WebBrowserTask();
task.URL = "http://yoururl.com";
task.Show();
Currently I have a website loaded in a WebBrowser component, which keeps changing stuff inside a certain <a> inside the page. In order for me to get the data, I have to create another WebRequest each 5 seconds, just to refresh the data (I think they're called dynamic pages). I've tried fetching the data from the WebBrowser (WebBrowser.DocumentText), but the value just remained the same, even though I am pretty sure it changed, because I can see it changed. I think the webrequest each 5 seconds takes up unnecesary memory space, and that this can be done easier.
Do you guys maybe know a way for me to do this?
Guessing at Winforms. You'll want to use the Document property to read back the DOM. Here's an example. Start a new Winforms project and drop a WebBrowser on the form. Then a label and a timer. Make the code look like this:
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
webBrowser1.Url = new Uri("http://stackoverflow.com/questions/10781011/get-source-of-webpage-in-webbrowser-c-sharp");
webBrowser1.DocumentCompleted += webBrowser1_DocumentCompleted;
timer1.Interval = 100;
timer1.Tick += new EventHandler(timer1_Tick);
}
void timer1_Tick(object sender, EventArgs e) {
var elem = webBrowser1.Document.GetElementById("wmd-input");
label1.Text = elem.InnerText;
}
void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e) {
timer1.Enabled = true;
}
}
The browser will navigate to your question. Type something in the Answer box, note how the label displays what you typed.
You'll need to tweak this code to work with your specific web page, alter the "wmd-input" element name. Use a DOM inspection tool to find the name. I like Firebug.
You could try to get the source via JavaScript.
Use the InvokeScript method to execute return document.documentElement.outerHTML;
This will return an Object which you should be able to type cast to a String.
Does anybody know how to click on a link in the WebBrowser control in a WinForms application and then have that link open in a new tab inside my TabControl?
I've been searching for months, seen many tutorials/articles/code samples but it seems as though nobody has ever tried this in C# before.
Any advice/samples are greatly appreciated.
Thank you.
Based on your comments, I understand that you want to trap the "Open In New Window" action for the WebBrowser control, and override the default behavior to open in a new tab inside your application instead.
To accomplish this reliably, you need to get at the NewWindow2 event, which exposes ppDisp (a settable pointer to the WebBrowser control that should open the new window).
All of the other potential hacked together solutions (such as obtaining the last link selected by the user before the OpenWindow event) are not optimal and are bound to fail in corner cases.
Luckily, there is a (relatively) simple way of accomplishing this while still using the System.Windows.Forms.WebBrowser control as a base. All you need to do is extend the WebBrowser and intercept the NewWindow2 event while providing public access to the ActiveX Instance (for passing into ppDisp in new tabs). This has been done before, and Mauricio Rojas has an excellent example with a complete working class "ExtendedWebBrowser":
http://blogs.artinsoft.net/mrojas/archive/2008/09/18/newwindow2-events-in-the-c-webbrowsercontrol.aspx
Once you have the ExtendedWebBrowser class, all you need to do is setup handlers for NewWindow2 and point ppDisp to a browser in a new tab. Here's an example that I put together:
private void InitializeBrowserEvents(ExtendedWebBrowser SourceBrowser)
{
SourceBrowser.NewWindow2 += new EventHandler<NewWindow2EventArgs>(SourceBrowser_NewWindow2);
}
void SourceBrowser_NewWindow2(object sender, NewWindow2EventArgs e)
{
TabPage NewTabPage = new TabPage()
{
Text = "Loading..."
};
ExtendedWebBrowser NewTabBrowser = new ExtendedWebBrowser()
{
Parent = NewTabPage,
Dock = DockStyle.Fill,
Tag = NewTabPage
};
e.PPDisp = NewTabBrowser.Application;
InitializeBrowserEvents(NewTabBrowser);
Tabs.TabPages.Add(NewTabPage);
Tabs.SelectedTab = NewTabPage;
}
private void Form1_Load(object sender, EventArgs e)
{
InitializeBrowserEvents(InitialTabBrowser);
}
(Assumes TabControl named "Tabs" and initial tab containing child control docked ExtendedWebBrowser named "InitialWebBrowser")
Don't forget to unregister the events when the tabs are closed!
private Uri _MyUrl;
System.Windows.Forms.WebBrowser browser = new System.Windows.Forms.WebBrowser();
browser.Navigating += new System.Windows.Forms.WebBrowserNavigatingEventHandler(browser_Navigating);
void browser_Navigating(object sender, System.Windows.Forms.WebBrowserNavigatingEventArgs e)
{
_MyUrl = e.Url;
e.Cancel;
}
The following code works, just follow the first reply for creating the ExtendedWebBrowser class.
I'm using this to open a new tab but it also works to open a new window using your browser and not IE.
Hope it helps.
private void Window_Loaded(object sender, RoutedEventArgs e)
{
if (current_tab_count == 10) return;
TabPage tabPage = new TabPage("Loading...");
tabpages.Add(tabPage);
tabControl1.TabPages.Add(tabPage);
current_tab_count++;
ExtendedWebBrowser browser = new ExtendedWebBrowser();
InitializeBrowserEvents(browser);
webpages.Add(browser);
browser.Parent = tabPage;
browser.Dock = DockStyle.Fill;
browser.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(browser_DocumentCompleted);
browser.DocumentTitleChanged += new EventHandler(Browser_DocumentTitleChanged);
browser.Navigated += Browser_Navigated;
browser.IsWebBrowserContextMenuEnabled = true;
public void InitializeBrowserEvents(ExtendedWebBrowser browser)
{
browser.NewWindow2 += new EventHandler<ExtendedWebBrowser.NewWindow2EventArgs>(Browser_NewWindow2);
}
void Browser_NewWindow2(object sender, ExtendedWebBrowser.NewWindow2EventArgs e)
{
if (current_tab_count == 10) return;
TabPage tabPage = new TabPage("Loading...");
tabpages.Add(tabPage);
tabControl1.TabPages.Add(tabPage);
current_tab_count++;
ExtendedWebBrowser browser = new ExtendedWebBrowser();
webpages.Add(browser);
browser.Parent = tabPage;
browser.Dock = DockStyle.Fill;
browser.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(browser_DocumentCompleted);
browser.DocumentTitleChanged += new EventHandler(Browser_DocumentTitleChanged);
browser.Navigated += Browser_Navigated;
tabControl1.SelectedTab = tabPage;
browser.Navigate(textBox.Text);
{
e.PPDisp = browser.Application;
InitializeBrowserEvents(browser);
}
I did a bit of research on this topic and one does not need to do all the COM plumbing that is present in the ExtendedWebBrowser class, as that code is already present in the generated Interop.SHDocVw. As such, I was able to use the more natural construct below to subscribe to the NewWindow2 event. In Visual Studio I had to add a reference to "Microsoft Internet Controls".
using SHDocVw;
...
internal WebBrowserSsoHost(System.Windows.Forms.WebBrowser webBrowser,...)
{
ParameterHelper.ThrowOnNull(webBrowser, "webBrowser");
...
(webBrowser.ActiveXInstance as WebBrowser).NewWindow2 += OnNewWindow2;
}
private void OnNewWindow2(ref object ppDisp, ref bool Cancel)
{
MyTabPage tabPage = TabPageFactory.CreateNewTabPage();
tabPage.SetBrowserAsContent(out ppDisp);
}
Please read http://bit.ly/IDWm5A for more info. This is page #5 in the series, for a complete understanding I had to go back and read pages 3 -> 5.
You simply cancel the new window event and handle the navigation and tab stuff yourself.
Here is a fully working example. This assumes you have a tabcontrol and at least 1 tab page in place.
using System.ComponentModel;
using System.Windows.Forms;
namespace stackoverflow2
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
this.webBrowser1.NewWindow += WebBrowser1_NewWindow;
this.webBrowser1.Navigated += Wb_Navigated;
this.webBrowser1.DocumentText=
"<html>"+
"<head><title>Title</title></head>"+
"<body>"+
"<a href = 'http://www.google.com' target = 'abc' > test </a>"+
"</body>"+
"</html>";
}
private void WebBrowser1_NewWindow(object sender, CancelEventArgs e)
{
e.Cancel = true; //stop normal new window activity
//get the url you were trying to navigate to
var url= webBrowser1.Document.ActiveElement.GetAttribute("href");
//set up the tabs
TabPage tp = new TabPage();
var wb = new WebBrowser();
wb.Navigated += Wb_Navigated;
wb.Size = this.webBrowser1.Size;
tp.Controls.Add(wb);
wb.Navigate(url);
this.tabControl1.Controls.Add(tp);
tabControl1.SelectedTab = tp;
}
private void Wb_Navigated(object sender, WebBrowserNavigatedEventArgs e)
{
tabControl1.SelectedTab.Text = (sender as WebBrowser).DocumentTitle;
}
}
}
There is no tabbing in the web browser control, therefor you need to handle the tabs yourself. Add a tab control above the web browser control and create new web browser controls when new tabs are being opened. Catch and cancel when the user opens new windows and open new tabs instead.