I want to print a html page from c# application but on a back ground thread because if I print the doc on main thread UI freezes for few seconds and I dont want that.
I have tried WebBrowser control but it need to be hosted on some form to get it work. Hosting this control is still acceptable but Print method needs to be called from same thread the control was created on. I tried calling Print method of WebBrowser from other thread but it neither work nor it give any error/exception. I have also tried InternetExplorerClass but it start iexplorer.exe and takes too much time.
Is there any other way in which I can print html page on a diffrent (non UI) thread?
I'd use a backgroundworker for this purpose - since you've already got a winform and everthing.
Drag a background worker and a webbrowser to your form and you can use the following code (UI freezes for milliseconds when the print is actually spooled);
I've used a test button (2) for the call;
using System.Threading;
private void button2_Click(object sender, EventArgs e)
{
if (!this.backgroundWorker1.IsBusy)
{
this.backgroundWorker1.RunWorkerAsync("http://www.stackoverflow.com/");
}
else
{
MessageBox.Show("Already working on that piece of paper!");
}
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
this.webBrowser1.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(webBrowser1_DocumentCompleted);
this.webBrowser1.Navigate((string)e.Argument);
//-- only when you need to read very bulky pages: Thread.Sleep(1000);
e.Result = true;
}
private void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
this.webBrowser1.Print();
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
this.webBrowser1.DocumentCompleted -= new WebBrowserDocumentCompletedEventHandler(webBrowser1_DocumentCompleted);
}
Does something like this not work?
webBrowser1.BeginInvoke((MethodInvoker)delegate{webBrowser1.Print();});
Related
i am making web browser in windows form by using c# where i can set values of loaded html's input fields automatically by clicking on button. when i simply put code in click event of button its work fine`
private void button1_Click(object sender, EventArgs e)
{
webBrowser1.Document.GetElementById("username").SetAttribute("value","admin");
webBrowser1.Document.GetElementById("password").SetAttribute("value","12345");
}`
but when i try to this via threading it gives me error
Specified cast is not valid?
private void button1_Click(object sender, EventArgs e)
{
Thread thread1 = new Thread(new ThreadStart(setvalues));
thread1.Start();
}
void setvalues()
{
webBrowser1.Document.GetElementById("username").SetAttribute("value","admin");
webBrowser1.Document.GetElementById("password").SetAttribute("value","12345");
Thread.Sleep(8000);
}
}
where i am doing mistake in code ? any error? am beginner i need help
You can't access forms controls in a separate thread. Try this in setvalues():
Invoke((Action)(() => {
webBrowser1.Document.GetElementById("username").SetAttribute("value","admin");
webBrowser1.Document.GetElementById("password").SetAttribute("value","12345");
}));
I have a Backgroundworker and I want to display a loading gif till the worker has finished.
My problem is that I cannot use
while(worker.IsBusy)
Thread.Sleep(50);
because that blocks the UI Thread and my GIF from updating it's frames.
Same problem occurs when using an AutoResetEvent and myAutoResetEvent.WaitOne();
Do you have any idea how to wait for the Backgroundworker to finish and still be able to display a GIF?
The whole point of the BackgroundWorker is to allow the UI to continue running.
And, you specifically want a GIF to continue to update with the BackgroundWorker is running.
So it's a perfect solution.
Clearly, though, you want the UI to be "non-iteractive" while the BackgroundWorker is running. Well, there's a fairly basic way to do that.
Here it is:
private void SaveButton_Click(object sender, EventArgs e)
{
SaveButton.Enabled = false;
backgroundWorker1.RunWorkerAsync();
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
System.Threading.Thread.Sleep(5000);
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
SaveButton.Enabled = true;
}
Basically, you just disable the controls that you don't want to user to interact with and re-enable them when the BackgroundWorker is done.
I am writing a Kiosk-type program for a media center PC. I have some pictureBoxes as my buttons, and would like a label or another pictureBox (acting as a label) to be visible/not visible and be triggered by a MouseEnter and MouseLeave event.
When the MouseLeave event happens(triggering Visible=false), a white box appears in place of the pictureBox or label that was previously there for a split second until the background image fills back in.
I have read up a little bit on using the BackgroundWorker to "pre-load" my pictureBox or labels. I am not sure that i am doing it right. I am very new to programming; i dabble here and there, and do not have any formal training in c#.
I am not looking for anyone to write the code for me, but i also am not objected to that either. A simple example of how to use it should suffice.
I have a background image (1920x1080) on my form. I think this image is actually having a harder time refreshing after the label or pictureBox's visibility is set to false.
private void pictureBox1_MouseEnter(object sender, EventArgs e)
{
this.pictureBox9.Visible = true;
}
private void pictureBox1_MouseLeave(object sender, EventArgs e)
{
this.pictureBox9.Visible = false;
}
I am attempting to use the backgroundWorker DoWork event, but really have no idea what i am doing.
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
this.pictureBox9.Visible = true;
this.pictureBox9.Visible = false;
}
My question is, "How do i use backgroundworker to effectively reduce the lag caused by changing visibilty of my pictureBoxes or lables?
The BackgroundWorker works like this:
BackgroundWorker workerOne = new BackgroundWorker();
BackgroundWorker workerTwo = new BackgroundWorker();
private void MyForm_Load(object sender, EventArgs e)
{
workerOne.DoWork += workerOne_DoWork;
workerTwo.DoWork += workerTwo_DoWork;
}
private void ThingOne_Click(object sender, EventArgs e)
{
workerOne.RunWorkerAsync();
}
private void ThingOne_Click(object sender, EventArgs e)
{
workerTwo.RunWorkerAsync();
}
void workerOne_DoWork(object sender, DoWorkEventArgs e)
{
//This will run as async and not interupt main thread
}
void workerTwo_DoWork(object sender, DoWorkEventArgs e)
{
//This will run as async and not interupt main thread
}
I've included two in the example. Basically the RunWorkerAsync breaks it off in its own thread.
I do not recommend using BackgroundWorker for this because the fact of changing the Visibility of a Visual Element requires the Main Thread and not a Worker Thread. What I recommend in any case is to handle the Opacity so you don't have to load the image again.
I'm writing a project in C# and I've run into a problem using backgroundworker to keep my form responsive whilst an expensive process runs. When I use the bgw method, I get an OutOfMemory exception. However, if I just run my ExpensiveMethod() directly without using bgw then I don't have any issues. Any ideas? I really want to be able to implement a progress bar whilst this method runs (its quite a time consuming process and the user needs to know how long is left). I am fairly new to C# and definitely a novice with threading.
Here is how I'm implementing my bgw and ExpensiveMethod():
private void btnGo_Click(object sender, EventArgs e)
{
myProgressBar.Visible = true;
bgw.RunWorkerAsync();
}
private void bgw_DoWork(object sender, DoWorkEventArgs e)
{
ExpensiveMethod();
}
private void bgw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
myProgressBar.Value = e.ProgressPercentage;
}
private void bgw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
myProgressBar.Visible = false;
}
private void ExpensiveMethod()
{
// do a big calculation and call this every so often:
bgw.ReportProgress((int)percentComplete);
}
This method, however, works fine with no memory exceptions, but obviously locks up the form whilst it runs:
private void btnGoThatWorks_Click(object sender, EventArgs e)
{
ExpensiveMethod();
}
Any ideas? I am on Windows7 32-bit.
It appears that the answer was that I was calling bgw.ReportProgress((int)percentComplete); far too often --- changing the code so it only reports every few percent seems to have fixed the issue.
private void AddMyScrollEventHandlers()
{
VScrollBar vScrollBar1 = new VScrollBar();
}
private void button1_Click(object sender, EventArgs e)
{
while (true)
{
if (vScrollBar1.Value + 1 < vScrollBar1.Maximum)
{
vScrollBar1.Value = vScrollBar1.Value + 1;
label1.Text = vScrollBar1.Value.ToString();
}
else
{
break;
}
System.Threading.Thread.Sleep(200);
}
}
private void button2_Click(object sender, EventArgs e)
{
// vScrollBar1.Scroll
}
I am new in C#. I was working on scroll. What I wanted here is, if anyone click button1 then scroll automatically move to the end and I wanted to show gradual value in label1. Also when someone click button2 scrolling stop.
Now the problem is label1 do not show gradual change in value. It shows value once when the scrolling stop.
Also when scrolling continue i,e when while loop is working I can not click on button2. Actually I can not click on the form even.
Someone please give me some idea how to do this.
This happens because the thread that is performing the task is busy, and it's the same thread that updates the UI. You can use a multithreading solution. Take a look at
BackgroundWorker
All the UI events run in the main thread of the application, so the application can only process one event at a time. When the application is processing an event, no other event will be processed.
Since you are doing a UI related work periodically, the best option is to use the Timer class:
Drop Timer from the toolbox into the form.
In the properties window, set the interval to 200.
Double click the timer object to create the Tick event handler.
Put this code in the newly created timer1_Tick method:
if (vScrollBar1.Value + 1 < vScrollBar1.Maximum)
{
vScrollBar1.Value = vScrollBar1.Value + 1;
label1.Text = vScrollBar1.Value.ToString();
}
else
{
timer1.Stop();
}
Change your methods as below:
private void AddMyScrollEventHandlers()
{
timer1.Start();
}
private void button2_Click(object sender, EventArgs e)
{
timer1.Stop();
}
Now you're done.
I would recommend using BackgroundWorker control, as suggested by Agustin Meriles. However, one more important thing to note is that You should use Control.Invoke(...) method to update controls from another thread.
I've modified Your code, tested it in a sample application and it seems to work correctly.
First, add a new BackgroundWorker control to Your form and assign backgroundWorker1_DoWork to its DoWork event.
Then, You can use the code below:
private void button1_Click(object sender, EventArgs e)
{
//code from here is moved to BackgroundWorker control
backgroundWorker1.RunWorkerAsync();
}
private void button2_Click(object sender, EventArgs e)
{
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
//while (true)
//the condition directly in the while looks more clear to me
while (vScrollBar1.Value + 1 < vScrollBar1.Maximum)
{
//update controls using Invoke method and anonymous functions
vScrollBar1.Invoke((MethodInvoker)delegate() { vScrollBar1.Value += 1; });
label1.Invoke((MethodInvoker)delegate() { label1.Text = vScrollBar1.Value.ToString(); });
//when called inside BackgroundWorker, this sleeps the background thread,
//so UI should be responsive now
System.Threading.Thread.Sleep(200);
}
}
If You have any problems when using this code, please let me know.
Update
As mentioned in the comments, You could also use ProgressChanged event of the BackgroundWorker. It requires some more changes in the code, but is more suitable in this case. You can find some information about it here: http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.progresschanged.aspx.
If You are not going to add any other code with more processing in the while loop, You can also use Timer control, as suggested by MD.Unicorn in his answer.