I have a C# winform project with a webbrowser control. I'm loading an HTML page with images into the webbrowser. Each image has a different ID:
<img src="F:\Temp\file12948.jpg" id="12948" width="180px">
Is there a way to pass the ID into a variable when clicking on the image so I can use the ID in my code? The path to the image can also be used as I can extract the number from there.
I have already searched here there and everywhere for a solution but can't find anything related.
You can dynamically attach to image's onClick event.
public class TestForm : Form
{
WebBrowser _WebBrowser = null;
public TestForm()
{
_WebBrowser = new WebBrowser();
_WebBrowser.ScriptErrorsSuppressed = true;
_WebBrowser.Dock = DockStyle.Fill;
this.Controls.Add(_WebBrowser);
WebBrowserDocumentCompletedEventHandler Completed = null;
Completed = (s, e) =>
{
//add onclick event dynamically
foreach (var img in _WebBrowser.Document.GetElementsByTagName("img").OfType<HtmlElement>())
{
img.AttachEventHandler("onclick", (_, __) => OnClick(img));
}
_WebBrowser.DocumentCompleted -= Completed;
};
_WebBrowser.DocumentCompleted += Completed;
var imgurl = "https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_120x44dp.png";
//_WebBrowser.Navigate("http://edition.cnn.com/2017/09/09/us/hurricane-irma-cuba-florida/index.html");
_WebBrowser.DocumentText = $"<html> <img src='{imgurl}' id=123 /> </html>";
}
void OnClick(HtmlElement img)
{
MessageBox.Show(img.GetAttribute("id"));
}
}
On simple way would be to use browser navigation. When clicking you can navigate to a special URL, then you handle the Navigating event and if the url is the special url you cancel the navigation and handle the data.
public MainWindow()
{
InitializeComponent();
br.NavigateToString(#"<img src=""F:\Temp\file12948.jpg"" id=""12948"" width=""180px"" >");
br.Navigating += this.Br_Navigating;
}
private void Br_Navigating(object sender, NavigatingCancelEventArgs e)
{
if(e.Uri.Host == "messages")
{
MessageBox.Show(e.Uri.Query);
e.Cancel = true;
}
}
This works if you have some control over the HTML. You could also set the URL from JS if you don't want to add the anchor.
Edit
The above version is for a WPF application. The winforms version is as follows:
public Form1()
{
InitializeComponent();
webBrowser1.DocumentText = #"<img src=""F:\Temp\file12948.jpg"" id=""12948"" width=""180px"" >";
webBrowser1.Navigating += this.webBrowser1_Navigating;
}
private void webBrowser1_Navigating(object sender, WebBrowserNavigatingEventArgs e)
{
if (e.Url.Host == "messages")
{
MessageBox.Show(e.Url.Query);
e.Cancel = true;
}
}
Related
I am working on a program that loads a webpage and calculates the load time. I want to give my program a URL and have it open an IE window at that page.
At first I was using Process.Start() to open the IE window, which works, but doesn't give me access to the WebBrowser.DocumentCompleted function. I am trying to create the IE window using a WebBrowser instance but I can't get the IE window to display.
using System;
using System.Windows.Forms;
namespace WebBrowserTest
{
public partial class Form1 : Form
{
WebBrowser IETestBrowser;
public Form1()
{
InitializeComponent();
IETestBrowser = new WebBrowser();
IETestBrowser.AllowNavigation = true;
IETestBrowser.Visible = true;
IETestBrowser.DocumentCompleted += ietb_DocumentCompleted;
}
private void LoadPageBtn_Click(object sender, EventArgs e)
{
IETestBrowser.Navigate("http://www.google.com");
IETestBrowser.Show();
TextDescriptionLbl.Text = "Loading Page...";
}
private void ietb_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
TextDescriptionLbl.Text = "Done!";
}
}
}
This code works, and the DocumentCompleted event is triggered properly. I want the webpage to be visibly displayed in an IE window. How do I get the WebBrowser to draw on screen?
public Form1()
{
InitializeComponent();
IETestBrowser = new WebBrowser();
IETestBrowser.AllowNavigation = true;
IETestBrowser.Visible = true;
IETestBrowser.DocumentCompleted += ietb_DocumentCompleted;
//Add the WebBrowser Control to the form
IETestBrowser.Left = 100;
IETestBrowser.Top = 100;
this.Controls.Add(IETestBrowser);
}
I'm designing an article editor for my company and I'd like to be able to show a live preview of the article in a separate WebBrowser window/control. The WebBrowser control needs to refresh the page every time the user changes anything in one of the fields for the article.
Previously, I had the WebBrowser control on the same form, but for space reasons, I had to break it out onto a separate form and access it using a button on the editor form. However, since I moved that control into a separate form, the WebBrowser gains focus on every refresh, meaning I can type one character and then I have to click back to the textbox I was typing in.
My question: Is there a way to refresh that preview page in the background without it stealing the focus so that I can update the preview to reflect what the user is typing without interrupting the user while typing?
Here are the methods for showing and refreshing the preview, respectively:
private void buttonShowPreview_Click(object sender, EventArgs e)
{
if (buttonShowPreview.Tag == null)
{
Form browserForm = new Form();
browserForm.FormClosing += new FormClosingEventHandler(delegate(Object form, FormClosingEventArgs args)
{
if (args.CloseReason == CloseReason.UserClosing)
{
args.Cancel = true;
browserForm.Hide();
previewShowing = false;
}
});
browserForm.Size = new System.Drawing.Size(1024, 768);
browserForm.DesktopLocation = new System.Drawing.Point(0, 0);
browserForm.Text = "Article Preview";
preview = new WebBrowser();
browserForm.Controls.Add(preview);
preview.Dock = DockStyle.Fill;
preview.Navigate("about:blank");
buttonShowPreview.Tag = browserForm;
}
Form previewForm = buttonShowPreview.Tag as Form;
previewForm.Show();
previewShowing = true;
RefreshPreview();
}
private void RefreshPreview(string jumpToAnchor)
{
if (preview != null)
{
preview.Document.OpenNew(true);
preview.Document.Write(structuredContent.GetStructuredContentHTML(content, jumpToAnchor, false));
preview.Refresh();
}
}
Based on the answer by Robberechts here, try disabling the parent Form, updating your WebBrowser, then re-enabling the parent Form again in the DocumentCompleted() event:
private void buttonShowPreview_Click(object sender, EventArgs e)
{
if (buttonShowPreview.Tag == null)
{
Form browserForm = new Form();
browserForm.FormClosing += new FormClosingEventHandler(delegate(Object form, FormClosingEventArgs args)
{
if (args.CloseReason == CloseReason.UserClosing)
{
args.Cancel = true;
browserForm.Hide();
}
});
preview = new WebBrowser();
preview.DocumentCompleted += preview_DocumentCompleted; // handle the DocumentCompleted() event
browserForm.Controls.Add(preview);
preview.Dock = DockStyle.Fill;
preview.Navigate("about:blank");
buttonShowPreview.Tag = browserForm;
}
Form previewForm = buttonShowPreview.Tag as Form;
previewForm.Size = new System.Drawing.Size(1024, 768);
previewForm.DesktopLocation = new System.Drawing.Point(0, 0);
previewForm.Text = "Article Preview";
RefreshPreview();
previewForm.Show();
}
private void RefreshPreview(string jumpToAnchor)
{
if (preview != null && preview.Parent != null)
{
preview.Parent.Enabled = false; // disable parent form
preview.Document.OpenNew(true);
preview.Document.Write(structuredContent.GetStructuredContentHTML(content, jumpToAnchor, false));
preview.Refresh();
}
}
private void preview_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
WebBrowser wb = sender as WebBrowser;
if (wb.Parent != null)
{
wb.Parent.Enabled = true; // re-enable parent form
}
}
I'm trying to use WebBrowser class, but of course it doesn't work.
My code:
WebBrowser browser = new WebBrowser();
browser.Navigate("http://www.google.com");
while(browser.DocumentText == "")
{
continue;
}
string html = browser.DocumentText;
browser.DocumentText is always "". Why?
You should use DocumentCompleted event, and if you don't have WebForms application, also ApplicationContext might be needed.
static class Program
{
[STAThread]
static void Main()
{
Context ctx = new Context();
Application.Run(ctx);
// ctx.Html; -- your html
}
}
class Context : ApplicationContext
{
public string Html { get; set; }
public Context()
{
WebBrowser browser = new WebBrowser();
browser.AllowNavigation = true;
browser.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(browser_DocumentCompleted);
browser.Navigate("http://www.google.com");
}
void browser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
Html = ((WebBrowser)sender).DocumentText;
this.ExitThread();
}
}
The WebBrowser isn't going to do it's job until the current thread finishes it's work, if you changed it to be something like this:
WebBrowser browser = new WebBrowser();
browser.Navigate("http://www.google.com");
browser.Navigated += (s, e) =>
{
var html = browser.DocumentText;
};
The variable will be set.
But, as others have mentioned, the document completed is a better event to attach to, as at that time, the entire document will be completed (appropriate name!)
WebBrowser browser = new WebBrowser();
browser.Navigate("http://www.google.com");
browser.DocumentCompleted += (s, e) =>
{
var html = browser.DocumentText;
html.ToString();
};
Attach to the DocumentCompleted event, the code is as below
browser.DocumentCompleted += (s, e) =>
{
string html = browser.DocumentText;
};
If you need the DocumentText you should handle the DocumentCompleted event
browser.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(browser_DocumentCompleted);
See event below
void browser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
WebBrowser wb = (WebBrowser)sender;
string text = wb.DocumentText;
}
Try something like this
string url = string.Empty:
string html = "http://www.google.com/";
string url = html;
if (!url.StartsWith("http://") && !url.StartsWith("https://"))
{
url = "http://" + url;
}
browser.Navigate(new Uri(url));
replace it within your While loop where necessary
I have a for loop and inside there is a navigate method for a browser. and it's suppose to load diffrent sites, but the problem is that it will start to load 1 site and before it will load it, it'll load another site. so I need to like pause it until it's completed.
I started to write an event to when the ProgressChanged event is at 100%.. than I figured I don't have any idea what to do next but I think it's a start.
Please help, Thanks!
Edit: I am using Forms as Roland said.
I assume you are doing windows forms programming. The event you want is DocumentCompleted Here's an example:
public Uri MyURI { get; set; }
public Form1()
{
InitializeComponent();
MyURI = new Uri("http://stackoverflow.com");
webBrowser1.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(webBrowser1_DocumentCompleted);
webBrowser1.Url = MyURI;
}
void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
if(e.Url == MyURI)
MessageBox.Show("Page Loaded");
}
For a list of URIs it's straight forward.
public int CurrentIndex = 0;
List<Uri> Uris;
public Form1()
{
InitializeComponent();
Uris = new List<Uri> { new Uri("http://stackoverflow.com"), new Uri("http://google.com/") };
webBrowser1.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(webBrowser1_DocumentCompleted);
webBrowser1.Url = Uris[CurrentIndex];
}
void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
WebBrowser browser = (WebBrowser)sender;
if (e.Url == Uris[CurrentIndex])
{
CurrentIndex++;
if (CurrentIndex < Uris.Count)
{
browser.Url = Uris[CurrentIndex];
}
}
}
I'm currently working on an app that technically interacts with an html page that uses dynamic content.
My problem is when I try to append data to the WBC the content isn't updating correctly.
namespace CheckList
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
.... code removed ....
private void button2_Click(object sender, EventArgs e)
{
if (textBox1.Text != null)
{
HtmlDocument doc = webBrowser1.Document;
HtmlElement row = doc.CreateElement("tr");
HtmlElement cell1 = doc.CreateElement("td");
HtmlElement cell2 = doc.CreateElement("td");
cell1.InnerHtml = "[X] " + textBox1.Text;
cell2.SetAttribute("class", "solved_2");
cell2.InnerHtml = "Unsolved";
row.AppendChild(cell1);
row.AppendChild(cell2);
doc.GetElementsByTagName("table")[0].AppendChild(row);
//doc.Write(doc.GetElementsByTagName("HTML")[0].OuterHtml);
webBrowser1.Document.Body.InnerHtml = doc.Body.InnerHtml;
}
}
}
}
What currently happens is, I click "add" it should add the html to the page and update and the javascript and what not should still load.
What happens is it adds the content, but the javascript doesn't work after I attempt to reload the content. The CSS stays in tact though, and the javascript isn't working after that point.
JS Source:
var showalert = true;
var file = "file:///C:/Users/Removed/Documents/Visual Studio 2010/Projects/CheckList/CheckList/bin/Release/";
initiate_instance();
function initiate_instance() {
//insert
$.get(file + "saved.html", function(data) {
//$("table#items").append("<tr><th width='70%'>Issue</th><th width='30%' class='right'>Solved</th></tr>");
$("table#items").html($("table#items").html() + data);
});
//change [X] into a link
$("table#items tr td").each(function() {
$(this).html($(this).html().replace("[X]", "<a onclick='return remove(this)' href='#'>[X]</a>"));
});
//change the css
$("table#items tr:odd").attr("class", "odd");
$("table#items tr td:eq(0)").attr("width", "70%");
$("table#items tr td:eq(1)").attr("width", "30%");
$("td.solved, td.solved_2").click(function() {
if($(this).attr("class") == "solved") {
$(this).attr("class", "solved_2");
$(this).text("Unsolved");
} else {
$(this).attr("class", "solved");
$(this).text("Solved");
}
if(showalert == true) {
alert("Remember, for these changes to keep effect please save before closing the program.");
showalert = false;
}
});
}
//delete rows
function remove(obj) {
if(showalert == true) {
alert("Remember, for these changes to keep effect please save before closing the program.");
showalert = false;
}
$(obj).parent().parent().remove();
return false;
}
TL;DR: Have you tried setting "AllowNavigation" to true?
If you need to prevent navigation, but still need to update the page, a method I've found that works requires:
Initializing the WebBrowser control's DocumentText property with empty HTML to initialize the internal objects (i.e.: Document, DomDocument, Document.Body, etc)
Allowing navigation and the revoking upon page completion (if needed)
Code:
namespace CheckList
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
// Initialize all the document objects
webBrowser1.DocumentText = #"<html></html>";
// Add the Document Completed event handler to turn off navigation
webBrowser1.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(webBrowser1_DocumentCompleted);
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
// Load default information via LoadHtml(string html);
LoadHtml(#"<html><head></head><body>Text!<script type='text/javascript' language='javascript'>alert('Aha!');</script></body></html>");
}
private void LoadHtml(string html)
{
webBrowser1.AllowNavigation = true;
// This will trigger a Document Completed event
webBrowser1.DocumentText = html;
}
private void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
// Prevent further navigation
webBrowser1.AllowNavigation = false;
// Clean-up the handler if no longer needed
}
private void button2_Click(object sender, EventArgs e)
{
// Do your document building
LoadHtml(doc.Body.Parent.OuterHtml);
}
}
}
I've found doing it this way:
Prevents users from navigating until allowed
Allows execution of JavaScript (immediately before OnDocumentCompleted fires)