Problems when printing in C# - c#

private void PrintHelpPage()
{
// Create a WebBrowser instance.
WebBrowser webBrowserForPrinting = new WebBrowser();
WebBrowser webBrowserForPrinting1 = new WebBrowser();
// Add an event handler that prints the document after it loads.
webBrowserForPrinting.DocumentCompleted +=
new WebBrowserDocumentCompletedEventHandler(PrintDocument);
webBrowserForPrinting1.DocumentCompleted +=
new WebBrowserDocumentCompletedEventHandler(PrintDocument);
// Set the Url property to load the document.
webBrowserForPrinting.Url = new Uri(#"F:\fichinha.html");
webBrowserForPrinting1.Url = new Uri(#"F:\fichinha2.html");
}
private void PrintDocument(object sender, WebBrowserDocumentCompletedEventArgs e)
{
// Print the document now that it is fully loaded.
((WebBrowser)sender).Print();
// Dispose the WebBrowser now that the task is complete.
((WebBrowser)sender).Dispose();
}
}
I have this code for printing an HTML file, what happens is:
Some of the letters do not appear! Including special characters and non-special...
Example: 1 of the pages: "Agora pode consultar" , appears "Agora pode cons tar"

have you set the encoding, e.g. UTF-8?
webBrowserForPrinting.Document.Encoding = Encoding.GetEncoding("UTF-8");
and the same for webBrowserForPrinting1

Related

CefSharp documentcompleted

I am trying to use cefshar browser in C# winforms and need to know how I know when page completely loaded and how I can get browser document and get html elements,
I just Initialize the browser and don't know what I should do next:
public Form1()
{
InitializeComponent();
Cef.Initialize(new CefSettings());
browser = new ChromiumWebBrowser("http://google.com");
BrowserContainer.Controls.Add(browser);
browser.Dock = DockStyle.Fill;
}
CefSharp has a LoadingStateChanged event with LoadingStateChangedArgs.
LoadingStateChangedArgs has a property called IsLoading which indicates if the page is still loading.
You should be able to subscribe to it like this:
browser.LoadingStateChanged += OnLoadingStateChanged;
The method would look like this:
private void OnLoadingStateChanged(object sender, LoadingStateChangedEventArgs args)
{
if (!args.IsLoading)
{
// Page has finished loading, do whatever you want here
}
}
I believe you can get the page source like this:
string HTML = await browser.GetSourceAsync();
You'd probably need to get to grips with something like HtmlAgility to parse it, I'm not going to cover that as it's off topic.
I ended up using:
using CefSharp;
wbAuthorization.AddressChanged += OnAddressChanged;
and
private void OnAddressChanged(
object s,
AddressChangedEventArgs e)
{
if (e.Address.StartsWith(EndUri))
{
ResultUri = new Uri(e.Address);
this.DialogResult = DialogResult.OK;
}
}
EndUri is the final page I want to examine and ResultUri contains a string I want to extract later. Just some example code from a larger class.

How to loop HTML printing when using a list?

I have a list, which contains paths to html files on my PC. I would like to loop through this list and print them all, in the same order they are in the list.
I tried to loop the code that i have found on msdn.microsoft.com for printing an HTML file.
List<string> AllHTMLsToPrint = new List<string>();
//things added to AllHTMLsToPrint list
foreach (string strHTMLToPrint in AllHTMLsToPrint)
{
PrintHelpPage(strHTMLToPrint);
}
private void PrintHelpPage(string strHTMLToPrint)
{
// Create a WebBrowser instance.
WebBrowser webBrowserForPrinting = new WebBrowser();
// Add an event handler that prints the document after it loads.
webBrowserForPrinting.DocumentCompleted +=
new WebBrowserDocumentCompletedEventHandler(PrintDocument);
// Set the Url property to load the document.
webBrowserForPrinting.Url = new Uri(strHTMLToPrint);
Thread.Sleep(100);
}
private void PrintDocument(object sender, WebBrowserDocumentCompletedEventArgs e)
{
// Print the document now that it is fully loaded.
((WebBrowser)sender).Print();
// Dispose the WebBrowser now that the task is complete.
((WebBrowser)sender).Dispose();
}
You have a design problem here. You walk your list of html pages to print. Then you open the page in a browser. When the page is loaded you print it.
BUT...
Loading the page may take longer than 100ms. This is the time after which the browser loads the next page. You should change your code so that the next page will load after the current one has been printed. You may not want to use a loop in this case but an index which you may want to increment after printing.
Should look similar to this (not tested):
List<string> AllHTMLsToPrint = new List<string>();
private int index = 0;
PrintHelpPage(AllHTMLsToPrint[index]);
private void PrintHelpPage(string strHTMLToPrint)
{
// Create a WebBrowser instance.
WebBrowser webBrowserForPrinting = new WebBrowser();
// Add an event handler that prints the document after it loads.
webBrowserForPrinting.DocumentCompleted +=
new WebBrowserDocumentCompletedEventHandler(PrintDocument);
// Set the Url property to load the document.
webBrowserForPrinting.Url = new Uri(strHTMLToPrint);
}
private void PrintDocument(object sender, WebBrowserDocumentCompletedEventArgs e)
{
// Print the document now that it is fully loaded.
((WebBrowser)sender).Print();
if (index < AllHTMLsToPrint.Count -1)
PrintHelpPage(AllHTMLsToPrint[++index]);
}
You've stated that you have a bunch of local html files.
The loading of local html files may not work by setting the URI.
You could try setting the DocumentStream instead. strHTMLToPrint must then contain the full/relative path to your local html file.
webBrowserForPrinting.DocumentStream = File.OpenRead(strHTMLToPrint);
Not sure what the exact issue is, but I would put this into a background worker so you don't hold up the main thread. I'd also move the loop into the document loaded system, that way as soon as it has loaded and printed it will move onto the next.
That said you haven't said what your code isn't doing.
public partial class Form1 : Form
{
internal List<string> AllHTMLsToPrint = new List<string>();
public Form1()
{
InitializeComponent();
}
public void StartPrinting()
{
//things added to AllHTMLsToPrint list, please note you may need to add file:/// to the URI list if it is a local file, unless it is compact framework
// start printing the first item
BackgroundWorker bgw = new BackgroundWorker();
bgw.DoWork += bgw_DoWork;
bgw.RunWorkerAsync();
/*foreach (string strHTMLToPrint in AllHTMLsToPrint)
{
PrintHelpPage(strHTMLToPrint);
}*/
}
void bgw_DoWork(object sender, DoWorkEventArgs e)
{
PrintHelpPage(AllHTMLsToPrint[0], (BackgroundWorker)sender);
}
private void PrintHelpPage(string strHTMLToPrint, BackgroundWorker bgw)
{
// Create a WebBrowser instance.
WebBrowser webBrowserForPrinting = new WebBrowser();
// Add an event handler that prints the document after it loads.
webBrowserForPrinting.DocumentCompleted += (s, ev) => {
webBrowserForPrinting.Print();
webBrowserForPrinting.Dispose();
// you can add progress reporting here
// remove the first element and see if we have to do it all again
AllHTMLsToPrint.RemoveAt(0);
if (AllHTMLsToPrint.Count > 0)
PrintHelpPage(AllHTMLsToPrint[0], bgw);
};
// Set the Url property to load the document.
webBrowserForPrinting.Url = new Uri(strHTMLToPrint);
}
}

Cannot get rendered html via WebBrowser

I want to get html code from website. In Browser I usually can just click on ‘View Page Source’ in context menu or something similar. But how can I automatized it? I’ve tried it with WebBrowser class but sometimes it doesn’t work. I am not web developer so I don’t really know if my approach at least make sense. I think main problem is that I sometimes get html where not all code was executed. Hence it is uncompleted. I have problem with e.g. this site: http://www.sreality.cz/en/search/for-sale/praha
My code (I’ve tried to make it small but runnable on its own):
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace WebBrowserForm
{
internal static class Program
{
[STAThread]
private static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
for (int i = 0; i < 10; i++)
{
Form1 f = new Form1();
f.ShowDialog();
}
// Now I can check Form1.List and see that some html is final and some is not
}
}
public class Form1 : Form
{
public static List<string> List = new List<string>();
private const string Url = "http://www.sreality.cz/en/search/for-sale/praha";
private System.Windows.Forms.WebBrowser webBrowser1;
public Form1()
{
this.webBrowser1 = new System.Windows.Forms.WebBrowser();
this.SuspendLayout();
this.webBrowser1.Dock = System.Windows.Forms.DockStyle.Fill;
this.webBrowser1.Name = "webBrowser1";
this.webBrowser1.TabIndex = 0;
this.ResumeLayout(false);
Load += new EventHandler(Form1_Load);
this.webBrowser1.ObjectForScripting = new MyScript();
}
private void Form1_Load(object sender, EventArgs e)
{
webBrowser1.Navigate(Url);
webBrowser1.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(webBrowser1_DocumentCompleted);
}
private void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
if (webBrowser1.ReadyState == WebBrowserReadyState.Complete)
{
// Final html for 99% of web pages, but unfortunately not for all
string tst = webBrowser1.Document.GetElementsByTagName("HTML")[0].OuterHtml;
webBrowser1.DocumentCompleted -= new WebBrowserDocumentCompletedEventHandler(webBrowser1_DocumentCompleted);
Application.DoEvents();
webBrowser1.Navigate("javascript: window.external.CallServerSideCode();");
Application.DoEvents();
}
}
[ComVisible(true)]
public class MyScript
{
public void CallServerSideCode()
{
HtmlDocument doc = ((Form1)Application.OpenForms[0]).webBrowser1.Document;
string renderedHtml = doc.GetElementsByTagName("HTML")[0].OuterHtml;
// here I sometimes get full html but sometimes the same as in webBrowser1_DocumentCompleted method
List.Add(renderedHtml);
((Form1)Application.OpenForms[0]).Close();
}
}
}
}
I would expect that in ‘webBrowser1_DocumentCompleted’ method I could get final html. It usually works, but with this site it doesn’t. So I’ve tried get html in my own code which should be executed in web site -> method ‘CallServerSideCode’. What is strange that sometimes I get final html (basically the same as if I do it manually via Browser) but sometimes not. I think the problem is caused because my script start before whole web site is rendered instead after. But I am not really sure since this kind of things are far from my comfort zone and I don’t really understand what I am doing. I’m just trying to apply something what I found on the internet.
So, does anyone knows what is wrong with the code? Or even more importantly how to easily get final html from the site?
Any help appreciated.
You should use WebClient class to download HTML page. No display control necessary.
You want method DownloadString
May be it will be helpful if you add calling of your external function to the end of the body and wrap it by Jquery "ondomready" function. I mean something like this:
private void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
if (webBrowser1.ReadyState == WebBrowserReadyState.Complete)
{
// Final html for 99% of web pages, but unfortunately not for all
string tst = webBrowser1.Document.GetElementsByTagName("HTML")[0].OuterHtml;
webBrowser1.DocumentCompleted -= new WebBrowserDocumentCompletedEventHandler(webBrowser1_DocumentCompleted);
HtmlElement body = webBrowser1.Document.GetElementsByTagName("body")[0];
HtmlElement scriptEl = webBrowser1.Document.CreateElement("script");
IHTMLScriptElement element = (IHTMLScriptElement)scriptEl.DomElement;
element.text = "$(function() { window.external.CallServerSideCode(); });";
body.AppendChild(scriptEl);
}
}
[ComVisible(true)]
public class MyScript
{
public void CallServerSideCode()
{
HtmlDocument doc = ((Form1)Application.OpenForms[0]).webBrowser1.Document;
string renderedHtml = doc.GetElementsByTagName("HTML")[0].OuterHtml;
// here I sometimes get full html but sometimes the same as in webBrowser1_DocumentCompleted method
List.Add(renderedHtml);
((Form1)Application.OpenForms[0]).Close();
}
}

c# WebBrowser DocumentText works once but not in a loop?

I am interested in checking the content of a website, the content changes frequently and when I view the website on any browser, it refreshes itself every 30 seconds. I want to know when the content has changed.
I am using winforms and I want to just click a button to start a loop, every 30 seconds. I don't want to hit the website too frequently, in fact the web pages own refresh is more than enough for my needs.
My code works when I click a button (btnCheckWebsite), if I wait a minute and then click btnCheckWebsite again, my message box pops up because the web page has changed. This is great however I want to do this in a while loop. When I un-comment my while loop, the DocumentText never changes. I have debugged it and for some reason it's the same text every time, even when the web page has changed in the real world, it stays the same in my code.
So my question is why can't I use a loop and what can I do instead to run this repeatedly without any input from me?
As a bonus, I would like to remove the .Refresh() I added this because it won't work without it however as I understand it, this refreshes the whole page. When I use a browser I see the page updating even when I don't refresh the whole page.
Just for background info, I did start by having a WebBrowser control on my form, the page refreshes automatically. I used the same code and have the same problem, interestingly, the WebBrowser control on my windows form refreshes by itself no problem, until I click btnCheckWebsite and then it stops refreshing! Also I know about webrequest but I don't know how to use it for my purposes.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;
namespace Check_Website
{
public partial class Form1 : Form
{
public WebBrowser _memoryWebBrowser = new WebBrowser();
String _previousSource = "emptySource";
public Form1()
{
InitializeComponent();
_memoryWebBrowser.Navigate(new Uri("http://www.randomurl.com/"));
}
private void btnCheckWebsite_Click(object sender, EventArgs e)
{
//I want to un-comment this while loop and let my code run itself but it stops working
//when I introduce my while loop.
//while (1 < 2 )
//{
//Thread.Sleep(30000);
checkWebsite();
//}
}
private void checkWebsite()
{
//Why do I need this refresh? I would rather not have to hit the web page with a refresh.
//When I view the webpage it refreshed with new data however when I use a WebBrowser
//the refresh just doesn't happen unless I call Refresh.
_memoryWebBrowser.Refresh();
Thread.Sleep(500);
while (((_memoryWebBrowser.ReadyState != WebBrowserReadyState.Complete) || (_memoryWebBrowser.DocumentText.Length < 3000)))
{
Thread.Sleep(1000);
}
String source = _memoryWebBrowser.DocumentText;
if ((source != _previousSource) && (_previousSource != "emptySource"))
{
//Hey take a look at the interesting new stuff on this web page!!
MessageBox.Show("Great news, there's new stuff on this web page www.randomurl.co.uk!!" );
}
_previousSource = source;
}
}
}
You'd need to do your processing upon DocumentCompleted event. This event is asynchronous, so if you want to do this in a loop, the execution thread must pump messages for this event to fire. In a WinFroms app, your UI thread is already pumping messages in Applicaiton.Run, and the only other endorsed way to enter nested message loop on the same thread is via a modal form (here's how it can be done, see in the comments).
Another (IMO, better) way of doing such Navigate/DocumentCompleted logic without a nested message loop is by using async/await, here's how. In the classic sense, this is not exactly a loop, but conceptually and syntactically it might be exactly what you're looking for.
You can catch the WebBrowser.Navigated Event to get notified when the page was reloaded. So you wouldn't need a loop for that. (I meant the ready loop)
Just navigate every 30 seconds to the page in a loop and in the Navigated Event you can check whether the site has changed or not.
You'd better hook up DocumentCompleted event to check its DocumentText property!
The WebBrowser Element is very buggy and has much overhead for your needs. Instead of that you should use WebRequest. Because you said you don't know how to use, here's an (working) example for you.
using System;
using System.Windows.Forms;
using System.Net;
using System.IO;
namespace Check_Website
{
public partial class Form1 : Form
{
String _previousSource = string.Empty;
System.Windows.Forms.Timer timer;
private System.Windows.Forms.CheckBox cbCheckWebsite;
private System.Windows.Forms.TextBox tbOutput;
public Form1()
{
InitializeComponent();
this.cbCheckWebsite = new System.Windows.Forms.CheckBox();
this.tbOutput = new System.Windows.Forms.TextBox();
this.SuspendLayout();
//
// cbCheckWebsite
//
this.cbCheckWebsite.AutoSize = true;
this.cbCheckWebsite.Location = new System.Drawing.Point(12, 12);
this.cbCheckWebsite.Name = "cbCheckWebsite";
this.cbCheckWebsite.Size = new System.Drawing.Size(80, 17);
this.cbCheckWebsite.TabIndex = 0;
this.cbCheckWebsite.Text = "checkBox1";
this.cbCheckWebsite.UseVisualStyleBackColor = true;
//
// tbOutput
//
this.tbOutput.Location = new System.Drawing.Point(12, 35);
this.tbOutput.Multiline = true;
this.tbOutput.Name = "tbOutput";
this.tbOutput.Size = new System.Drawing.Size(260, 215);
this.tbOutput.TabIndex = 1;
//
// Form1
//
this.ClientSize = new System.Drawing.Size(284, 262);
this.Controls.Add(this.tbOutput);
this.Controls.Add(this.cbCheckWebsite);
this.Name = "Form1";
this.Load += new System.EventHandler(this.Form1_Load);
this.ResumeLayout(false);
this.PerformLayout();
timer = new System.Windows.Forms.Timer();
timer.Interval = 30000;
timer.Tick += timer_Tick;
}
private void Form1_Load(object sender, EventArgs e)
{
timer.Start();
}
void timer_Tick(object sender, EventArgs e)
{
if (!cbCheckWebsite.Checked) return;
WebRequest request = WebRequest.Create("http://localhost/check_website.html");
request.Method = "GET";
WebResponse response = request.GetResponse();
string newContent;
using (var sr = new StreamReader(response.GetResponseStream()))
{
newContent = sr.ReadToEnd();
}
tbOutput.Text += newContent + "\r\n";
if (_previousSource == string.Empty)
{
tbOutput.Text += "Nah. It's empty";
}
else if (_previousSource == newContent)
{
tbOutput.Text += "Nah. Equals the old content";
}
else
{
tbOutput.Text += "Oh great. Something happened";
}
_previousSource = newContent;
}
}
}

Webkit.Net wait for page to be fully loaded

I'm trying to make an C# windows form application, with an webbrowser.
I'm using the webkit browser: Link to the browser
The webbrowser did i put in an class file, so i can acces it through all the forms i'm going to use.
The code that's generate the webbrowser:
public static WebKit.WebKitBrowser mainBrowser = new WebKitBrowser();
I'm having this piece of code that give's some problems:
globalVars.mainBrowser.Navigate("http://www.somesite.com/");
while (globalVars.mainBrowser.IsBusy)
{
System.Threading.Thread.Sleep(500);
}
globalVars.mainBrowser.Document.GetElementById("user").TextContent = "User Name";
But it's not working. If i do an message box after the while, it shows up before it's possible to render the page...
So what is the best way to wait until the site is fully loaded?
UPDATE 1
In an standalone class file, am i making the webkit controll like this:
public static WebKit.WebKitBrowser mainBrowser = new WebKitBrowser();
And in an form, i've got now this code (thanks to Tearsdontfalls):
public void loginthen()
{
globalVars.mainBrowser.DocumentCompleted += mainBrowser_DocumentCompleted;
globalVars.mainBrowser.Navigate("http://www.somesite.com/");
}
void mainBrowser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
var send = sender as WebKit.WebKitBrowser;
if (send.Url == e.Url)
{
MessageBox.Show("Inloggen");
globalVars.mainBrowser.Document.GetElementById("user").TextContent = "User Name";
}
}
But no messagebox shows up. But if i use an local (on the same form) webkit browser, i'm getting te MessageBox. But then the user field isn't filled in.
Even an breakpoint in the documentCompleted event, isn't triggerd. So it looks like the event listner isn't working...
So why is it not working?
You can simply create an event listener on the Document Completed Event on your Webbrowser, or you can create it dynamically like that:
globalVars.mainbrowser.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(mainbrowser_DocumentCompleted);
Where mainbrowser_DocumentCompleted is the name of the void where you can do sth like this(I used the names of your provided code):
void browser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e) {
var send = sender as WebKit.WebKitBrowser;
if (send.Url == e.Url) {
globalVars.mainBrowser.Document.GetElementById("user").TextContent = "User Name";
}
}
Adding the following piece of code let the events fire when the browser is in invisible mode.
using (Bitmap bmp = new Bitmap(webKitBrowser.Width, webKitBrowser.Height))
{
webKitBrowser.DrawToBitmap(
bmp,
new Rectangle(
webKitBrowser.Location.X,
webKitBrowser.Location.Y,
webKitBrowser.Width,
webKitBrowser.Height
)
);
}

Categories