Thanks to JP Hellemons my browser is now able to load the favicon of a page that's loaded.
This way, I'm able to change the icon of my Windows form to the favicon of the site.
Now I'd like to change my form-icon when the user switches tabs, to the form-icon is always the same as the visible site.
I had made a little code and put it in the SelectedIndexChanged-event.
However, when I open a new tab, my code switches tabs, creates a browser element inside the tab and then navigates to the homepage.
This results in an error when I use my code, as the favicon-method can't find the new browser yet :s
Here are my codes:
a) Retreiving the
favicon
b) Changing the form-icon (I've placed this code in the
SelectedIndexChanged-event method)
private void tabs_SelectedIndexChanged(object sender, EventArgs e) { // tabs is the TabControl
this.Icon = favicon(GetActiveBrowser().Url);
}
// this code returns the active WebBrowser-element
private WebBrowser GetActiveBrowser() {
return (WebBrowser)tabs.SelectedTab.Controls[0];
}
c) The code that creates the new tab, when I press btnNewTab
private void btnNewTab_Click(object sender, EventArgs e) {
// new tab
TabPage page = new TabPage("... Loading ...");
tabs.TabPages.Add(page);
this.Icon = Properties.Resources.loading1;
tabs.SelectedTab = page;
// include browser
WebBrowser browser = new WebBrowser();
browser.Parent = page;
browser.Dock = DockStyle.Fill;
browser.Visible = true;
browser.DocumentCompleted += new System.Windows.Forms.WebBrowserDocumentCompletedEventHandler(this.browser_DocumentCompleted);
browser.StatusTextChanged += new EventHandler(browser_StatusTextChanged);
browser.DocumentTitleChanged += new EventHandler(browser_DocumentTitleChanged);
browser.ProgressChanged += new WebBrowserProgressChangedEventHandler(browser_ProgressChanged);
browser.ContextMenuStrip = contextBrowser;
navigate(Properties.Settings.Default.BrowserHome);
} // open URL in new tab
The question is easy, the answer seems more difficult:
How can I make my form wait untill the WebBrowser element is created before seeking the favicon?
Related
I am using C# to login to a local web page.
I am using webBrowser in order to display the page after the log.
First, I navigate to page then I fill the username & password then I invoke a click.The element to be clicked is recognized; so I assume that the click happened. But the result page isn't showing, nothing appears when I execute.
I tried this:
public WebBrowser webBrowser;
public MainWindow()
{
InitializeComponent();
webBrowser = new WebBrowser();
webBrowser.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(LoginEvent);
webBrowser.AllowNavigation = true;
webBrowser.Navigate("http://192.168.1.100/login.html");
}
private void LoginEvent(object sender, WebBrowserDocumentCompletedEventArgs e)
{
WebBrowser webBrowser = sender as WebBrowser;
//To execute the event just one time
webBrowser.DocumentCompleted -= LoginEvent;
//load page's document
HtmlDocument doc = webBrowser.Document;
doc.GetElementById("u").SetAttribute("value", "admin");
doc.GetElementById("pw").SetAttribute("value", "123456");
foreach (HtmlElement elem in doc.GetElementsByTagName("a"))
{
elem.InvokeMember("click");
}
}
Can anyone help me please to figure why the page isn't showing?
1) Your WebBrowser object is a local variable in your MainWindow() constructor.
This object is being deposed once the MainWindow constructor ends.
You need to declare the WebBrowser object as a class member.
2) There might be a multiple DocumentComplete events being fired. You need to filter out all iFrame events and wait before the page being fully loaded:
private void LoginEvent(object sender, WebBrowserDocumentCompletedEventArgs e)
{
// filter out non main documents
if (e.Url.AbsolutePath != (sender as WebBrowser).Url.AbsolutePath)
return;
//To execute the event just one time
webBrowser.DocumentCompleted -= LoginEvent;
//load page's document
HtmlDocument doc = webBrowser.Document;
doc.GetElementById("u").SetAttribute("value", "admin");
doc.GetElementById("pw").SetAttribute("value", "123456");
foreach (HtmlElement elem in doc.GetElementsByTagName("a"))
{
elem.InvokeMember("click");
}
}
Here is my code.
public partial class MainScreen : Form
{
public MainScreen()
{
InitializeComponent();
//Initializing the browser in class Browser
Browser brow = new Browser();
//Hiding the user control that contains the browser UI
this.browserPanel1.Visible = false;
//Adding the browser to my main form's user control
this.browserPanel1.Controls.Add(brow.chromeBrowser);
}
I have a button which has the function to show the user control that was initially hidden.
private void button1_Click(object sender, EventArgs e)
{
this.browserPanel1.Visible = true;
}
I am clicking this button after a minute.
Normally, the website should be fully loaded before I make user control visible again by the button click. But when I click on the button, the browser takes the same time as if it was created at the moment. Why is the website not pre-loaded into the browser?
//The Browser class
class Browser
{
public ChromiumWebBrowser chromeBrowser;
public Browser()
{
CefSettings settings = new CefSettings();
Cef.Initialize(settings);
chromeBrowser = new ChromiumWebBrowser("https://google.com");
chromeBrowser.Dock = DockStyle.Fill;
}
}
There is a similar discussion on github here: CefWebBrowser display dependent
The URL is not being loaded because you add ChromiumWebBrowser on a hidden panel, and browser never becomes created on a hidden panel (due too the fact that winforms creates controls in a deffered manner). On the other side, the Load method waits until the browser is created. But there is a special .CreateControl method which you can use as a workaround.
Taking the discussion on github into account you should add chromeBrowser.CreateControl(); to your Browser constructor, so the Browser class should look like:
class Browser
{
public ChromiumWebBrowser chromeBrowser;
public Browser()
{
CefSettings settings = new CefSettings();
Cef.Initialize(settings);
chromeBrowser = new ChromiumWebBrowser("https://google.com");
chromeBrowser.Dock = DockStyle.Fill;
chromeBrowser.CreateControl();
}
}
I am working for a screen scrapping application from windows application
I can automatically navigate through login page and all the pages using the we browser methods and sometimes having to use the '.Click' to trigger buttons on some of the pages.
Here's the problem. When I do the final 'click' to get my data, web browser opens up a new explorer window(pop up windows) that contains the another link button and I have to do click on this link button using c# to get my final data.
How can I access the new window(pop up window) to scrape it?
I am using below code and this code open the URL in new pop up window.
HtmlElement toollinkbutton = WebBrowser1.Document.Window.Document.Body.Document.GetElementsByTagName("a")[48];
toollinkbutton .InvokeMember("click");
The new window may be due to target="_blank" or javascript and using InvokeMember will result in the new window opening. Add a handler to the WebBrowser control NewWindow event and handle the click by calling Navigate() instead.
private string url = "";
public Form1()
{
InitializeComponent();
WebBrowser1.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(webBrowser1_DocumentCompleted);
WebBrowser1.NewWindow += new System.ComponentModel.CancelEventHandler(webBrowser1_NewWindow);
}
void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
HtmlElementCollection links = WebBrowser1.Document.Links;
foreach (HtmlElement var in links)
{
var.AttachEventHandler("onclick", LinkClicked);
}
}
private void LinkClicked(object sender, EventArgs e)
{
HtmlElement link = WebBrowser1.Document.ActiveElement;
url = link.GetAttribute("href");
}
void webBrowser1_NewWindow(object sender, System.ComponentModel.CancelEventArgs e)
{
WebBrowser webBrowser = (WebBrowser)sender;
HtmlElement link = webBrowser.Document.ActiveElement;
Uri urlNavigated = new Uri(link.GetAttribute("href"));
WebBrowser1.Navigate(url);
e.Cancel = true;
}
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.
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.