How to use progressbar, backgroundworker, windows form together in C#? - c#

I am stuck on an issue where I am using Backgroundworker to show the progress of my work in a progress bar. Code used for backgroundworker:-
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
Thread.Sleep(200);
for (int i = 0; i <= 100; i++)
{
Delegate del= new DELEGATE(simulateHeavyWork);
this.Invoke(del);
backgroundWorker1.ReportProgress(i);
if (backgroundWorker1.CancellationPending)
{
e.Cancel = true;
backgroundWorker1.ReportProgress(0);
return;
}
}
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
progressBar1.Value = e.ProgressPercentage;
percentLabel.Text = e.ProgressPercentage.ToString() + "%";
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Cancelled)
{
MessageBox.Show("Cancelled");
}
else
{
MessageBox.Show("Completed");
}
}
I have created a delegate on the code:-
public partial class Form1 : Form
{
private delegate void DELEGATE();
public Form1()
{
InitializeComponent();
}
private void simulateHeavyWork()
{
Thread.Sleep(100);
...lines of code to perform some search logs operation..
....
}
}
The functionality I want to achieve is that progress bar should report the progress of my function simulateHeavyWork() which is actually using UI thread as it needs to take input from my form controls and update it as well.
Now the problem which is happening is that code is actually calling simulateHeavyWork() and gives the output that is updating ui controls and work is done. (Note: I have used delegate here to avoid error cross controls running on ui thread as my function needs to use UI controls.)
Once that is done, it starts updating progress bar and which is wrong and looks like it calls simulateHeavyWork again and again with the gap of sleep(100).

user3222101, as Andy stated before, you are running simulateHeavyWork() continuously. Moreover, by calling Invoke you are running this method in the UI thread which cause an extra sleep in the UI thread. Basically Invoke uses the message loop (pump) of the Control you use it on (Form1 in that case) and put your delegate to the queue of the UI thread in order to execute. This is not a good practice I think, due to the Sleep() call and time consuming log operations in your simulateHeavyWork() method.
I hope, understand you problem clearly.What I suggest is separation of the time consuming log operations from UI thread. Do not spend the valuable time of UI thread with slow and boring I/O operations. Get the values from the controls (using Invoke in the BackgroundWorker as I will explain below), do whatever you want in BackgroundWorker and update your GUI (again using Invoke) without touching the UI thread for this kind of heavy tasks.
As Andy suggested, you can pass data via the parameter of RunWorkerAsync and you should create a class which can store any data you need (because it accepts only one parameter). However, you can get the values from your Form whenever you need from another thread by using Invoke. Invoke
method also returns the value from your delegate (please see the example at the link below) and this gives you a chance to get the values of your controls on the form. Create a delegate which returns an object of type class that you crated for RunWorkerAsync and use this values in the BackgroundWorker thread. Please, have a look at the example in here.
public static string GetTextThreadSafe(this TextBox box)
{
return GetTextBoxText(box);
}
Also, example uses Func<...> in order to return value.
By this way you can sleep (in BackgroundWorker thread) for a while then get the values from your controls (current values) and do whatever you want (again in BackgroundWorker thread). I think, this improves your code.

From your question: "which is wrong and looks like it calls simulateHeavyWork again and again with the gap of sleep(100)."
Of course it calls. Just look at your code:
for (int i = 0; i <= 100; i++)
{
Delegate del= new DELEGATE(simulateHeavyWork);
this.Invoke(del);
So you are calling simulateHeavyWork 100 times here. And since you've typed Thread.Sleep(100); in the body of simulateHeavyWork - gap between calls is about Sleep(100)

Related

C# Invoke button control on separate thread

I have seen a lot of questions about how to edit controls on c# form from a different thread but none make much sense to me. I understand that you can not change any UI from another thread than it's main. To make this work you have to use invoke and from there safely edit the control?
I have a button that starts writing in a file and the moment you press the button the button itself gets disabled so you can not start multiple threads that do exactly the same. When the writing is done I want the button to be available again but I can not get it working on this other thread.
I have this as the Generate_Click event from the form.
private void Generate_Click(object sender, EventArgs e)
{
Generate.Enabled = false;
int x = 512;
int y = 512;
MBrot mbrot = new MBrot(x, y);
PB_Update lb = new PB_Update(0, y, Generator_PB, Generate, mbrot, this);
lb.Start();
}
And this is in PB_Update.cs the ThreadWork() function, when the while loop is done the writing to the file is done and so is the thread so its ended and given a messagebox with "finished" now as last the button needs to be enabled again.
public void ThreadWork()
{
while (true)
{
if (currValue_ >= maxValue_)
break;
ThreadTick();
}
mb_.StopBrot();
t_.Interrupt();
MessageBox.Show("Finished!");
Generate_.Enabled = true;
}
For WinForms you can execute directly on the thread which the control was created on through the Control.BeginInvoke method, you can use Control.Invoke as well but, Control.BeginInvoke is preferred for UI operations.
public void ThreadWork()
{
while (true)
{
if (currValue_ >= maxValue_)
break;
ThreadTick();
}
mb_.StopBrot();
t_.Interrupt();
MessageBox.Show("Finished!");
Generate_.BeginInvoke((Action)delegate()
{
Generate_.Enabled = true;
});
}
Somehow, get a reference to the form that hosts the generate_ button (let's call it myform). Then, at the bottom of your ThreadWork:
myform.Invoke(new Action(() => {
myform.SetGenerateEnabled();
}));
And then inside your form create that method that enables the button appropriately. (I used a method rather than just updating the button directly so that you don't publicly expose the button.)
This executes the commands inside the { ... } on myform's thread, which is a UI thread, because it is UI. At least, that's what I understand. This is how I do all of my UI updating from other threads.
Here's a simple example of a way to kick off an async task that disables a button for 5 seconds and then enables it again. Meanwhile, the rest of the UI is functional.
Note that this async method exists in the same class as your Generate_Click event, and runs on the UI thread. This means that it can enable and disable the button. But the long running task executes on a separate thread, so it doesn't lock the UI.
Hopefully this sample provides you a base to modify for your own code:
private void Generate_Click(object sender, EventArgs e)
{
DisableButton(sender as Button, 5);
}
private async void DisableButton(Button sender, int secondsToDisable)
{
sender.Enabled = false;
// In your code, you would kick off your long-running process here as a task
await Task.Run(()=>Thread.Sleep(TimeSpan.FromSeconds(secondsToDisable)));
sender.Enabled = true;
}

WPF interface is updated only after the DispatcherTimer thread finishes

I have a WPF application and I am working with the .NET Framework 4.0 and C#. My application consists of an interface with several controls. In particular I have a task that needs to be executed periodically every 10 seconds. In order to execute it I use a System.Windows.Threading.DispatcherTimer. The ViewModel looks like this:
public class WindowViewModel {
protected DispatcherTimer cycle;
public WindowViewModel() {
this.cycle = new DispatcherTimer(DispatcherPriority.Normal,
System.Windows.Application.Current.Dispatcher);
this.cycle.Interval = new TimeSpan(0,0,0,0,10000);
this.cycle.Tick += delegate(object sender, EventArgs e) {
for (int i = 0; i < 20; i++) {
// Doing something
}
};
this.cycle.Start;
}
}
As I said the routine called periodically does something. In particular there is some heavy logic there which causes that routine to take some seconds to execute and complete. Well it is a different thread so I should be ok and the interface is not supposed to freeze.
The problem is that that routine causes the viewmodel to be updated. Several data are updated, and the corresponding View is bound to those data. What happens is that all updated data are refreshed once at a time when the routine completes. I want data to be updated during the thread execution.
In particular inside that routine I have a for cycle. Well at the exit of the cycle everything is updated in the interface. How to achieve this? Where am i doing wrong?
The DispatcherTimer uses the supplied Dispatcher to run the timer callback.
If you take a look at the docs for Dispatcher, there's a clue:
Provides services for managing the queue of work items for a thread.
So, by using the System.Windows.Application.Current.Dispatcher, you're using the Dispatcher that manages "the queue of work items" for the UI thread.
To run your work in the ThreadPool instead, you could either use System.Threading.Timer or use ThreadPool.QueueUserWorkItem in your DispatcherTimer callback.
If you combine this with the following extension method, it becomes easy to marshal any UI specific stuff back to the Dispatcher when you finish your heavy workload:
public static class DispatcherEx
{
public static void InvokeOrExecute(this Dispatcher dispatcher, Action action)
{
if (dispatcher.CheckAccess())
{
action();
}
else
{
dispatcher.BeginInvoke(DispatcherPriority.Normal,
action);
}
}
}
then...
this.cycle.Tick += delegate(object sender, EventArgs e) {
ThreadPool.QueueUserWorkItem(_ => {
for (int i = 0; i < 20; i++) {
// Doing something heavy
System.Windows.Application.Current.Dispatcher.InvokeOrExecute(() => {
//update the UI on the UI thread.
});
}
});
};

Theads to keep alive a process but useless otherwise

Hello guys I have a question regardless a old code a client needed a update.
This code add a thread.sleep(500) to keep the service alive, is reading from a com port some calls, and sending a alarm to other pcs now this time when I was sending some information to the machine in question this error pops out
Cross-thread operation not valid: Control 'textBox1' accessed from a thread other than the thread it was created on.
private void port_DataReceived(object sender, SerialDataReceivedEventArgs e) {
Thread.Sleep(500);
string data = port.ReadExisting();
//try
//{
if (textBox1.TextLength == 30000)
{
textBox1.Text = "";
}
//}
//catch (Exception) {}
this.BeginInvoke(new setTextDeleg(si_DataRecived), new object[]{
data});
}
This is the function that writes on the com machine, does making a exception to eat the error is ok, or is there another better way to handle it?
PD: Sorry for my bad english, this is on C# 2008 vs
You should modify GUI components like textboxes and labels only from the thread that created them which is the main thread. You may take a look at BackgroundWorker which simplifies this task in WinForms application. And here's another useful article illustrating the usage of the InvokeRequired property and the Invoke method.
It's not a good idea to simply swallow this exception. The exception is occurring because you are not allowed to modify UI components from any thread other than the UI thread (the thread that created them). Instead, check out this MSDN article on how to pass information between worker threads (your thread that sleeps) and UI threads to update the text box in the correct manner.
The problem is because Windows Forms Controls are not thread-safe, and it would seem that the control is not being invoked properly for a thread-safe call. You can use the BackgroundWorker class or you can invoke it yourself. Here is a small code example.
// Delegate used by our worker thread to invoke our control
private delegate void ProgressDelegate(int value);
// Callback method used for our delegate
private void ProgressCallback(int value) {
progressBar1.Value = value;
}
protected override void OnShown(EventArgs e) {
Thread thread = new Thread(new ThreadStart(MyThreadWorker));
thread.IsBackground = true;
thread.Start();
}
// Thread method
private void MyThreadWorker() {
// Setup the delegate
ProgressDelegate mydelegate = new ProgressDelegate(ProgressCallback);
// Do some work
int pos = 0;
do {
pos++;
// Make a thread-safe call to our control and invoke our callback on the original thread
// Original thread: The thread the form and control were created on
progressBar1.Invoke(mydelegate, pos);
} while (pos < 100);
}
I'm guessing what some of your other code looks like, but you could probably move this
if (textBox1.TextLength == 30000)
{
textBox1.Text = "";
}
to the si_DataRecived method, so that it gets executed as part of the BeginInvoke call, the target of which will execute on the main (UI) thread.

C# threading issue

To play a bit with threading, delegates and backgroundworkers, I'm putting together a few small applications, I'm having a bit of trouble with one of them.
I've a Windows form, with a textbox, a button and a richttext.
When I press the button, the text in the textbox is used as a paramter to instantiate a class, like this:
public partial class Form1 : Form
{
private BackgroundWorker backgroundWorker;
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
backgroundWorker = new BackgroundWorker();
backgroundWorker.DoWork += new DoWorkEventHandler(worker_DoWork);
backgroundWorker.RunWorkerAsync();
}
void worker_DoWork(object sender, DoWorkEventArgs e)
{
new Thread((ThreadStart)delegate()
{
this.BeginInvoke((ThreadStart)delegate()
{
foreach (string line in textBox1.Lines)
{
Dig digger = new Dig(line, textBox1.Text);
digger.DomainChecked += new Dig.DomainCheckedHandler(OnUpdateTicker);
string response = digger.GetAllInfo();
richTextBox1.AppendText(response);
Application.DoEvents();
}
});
}).Start();
}
void OnUpdateTicker(string msg)
{
new Thread((ThreadStart)delegate()
{
this.BeginInvoke((ThreadStart)delegate()
{
label4.Text = msg;
Application.DoEvents();
});
}).Start();
}
}
When debugging I run into a 'textBox1.Lines' threw an exception of type 'Microsoft.VisualStudio.Debugger.Runtime.CrossThreadMessagingException'
Any tips on how to solve this problem?
First, there is no need to create new threads inside DoWork; the whole idea with the BackgroundWorker is that DoWork is executed on a separate thread. Second, since DoWork is executed on a separate thread and UI controls can be modified only on the UI thread, you need to invoke those updates correctly. So, a rewritten version of worker_DoWork could look like this:
void worker_DoWork(object sender, DoWorkEventArgs e)
{
foreach (string line in textBox1.Lines)
{
Dig digger = new Dig(line, textBox1.Text);
digger.DomainChecked += new Dig.DomainCheckedHandler(OnUpdateTicker);
string response = digger.GetAllInfo();
richTextBox1.Invoke((Action) delegate { richTextBox1.AppendText(response); });
}
}
Note how the code does not explicitly spawn any new threads, and also how the AppendText method call is done through a Control.Invoke call, forcing it to execute on the UI thread.
The main reason is that the textbox is not owned by the background thread.
Your UI thread owns all the UI objects, and you're spinning up a background thread when a button is pressed. That background thread should not have access to any UI objects.
If you want the value of the textbox to be used, you'll need to pass it to your background thread another way.
Have a look here for an explanation (and solution).
You can only update controls on the main thread from the main thread itself, unless you explicitly tell your program that it's ok to do, by using the .Invoke method of the control.
From: http://www.albahari.com/threading/part3.aspx
Control.Invoke
In a multi-threaded Windows Forms application, it's illegal to call a method or property on a control from any thread other than the one that created it. All cross-thread calls must be explicitly marshalled to the thread that created the control (usually the main thread), using the Control.Invoke or Control.BeginInvoke method. One cannot rely on automatic marshalling because it takes place too late – only when execution gets well into unmanaged code, by which time plenty of internal .NET code may already have run on the "wrong" thread – code which is not thread-safe.

How do I run a simple bit of code in a new thread?

I have a bit of code that I need to run in a different thread than the GUI as it currently causes the form to freeze whilst the code runs (10 seconds or so).
Assume I have never created a new thread before; what's a simple/basic example of how to do this in C# and using .NET Framework 2.0 or later?
Good place to start reading is Joe Albahari.
If you want to create your own thread, this is as simple as it gets:
using System.Threading;
new Thread(() =>
{
Thread.CurrentThread.IsBackground = true;
/* run your code here */
Console.WriteLine("Hello, world");
}).Start();
BackgroundWorker seems to be best choice for you.
Here is my minimal example. After you click on the button the background worker will begin working in background thread and also report its progress simultaneously. It will also report after the work completes.
using System.ComponentModel;
...
private void button1_Click(object sender, EventArgs e)
{
BackgroundWorker bw = new BackgroundWorker();
// this allows our worker to report progress during work
bw.WorkerReportsProgress = true;
// what to do in the background thread
bw.DoWork += new DoWorkEventHandler(
delegate(object o, DoWorkEventArgs args)
{
BackgroundWorker b = o as BackgroundWorker;
// do some simple processing for 10 seconds
for (int i = 1; i <= 10; i++)
{
// report the progress in percent
b.ReportProgress(i * 10);
Thread.Sleep(1000);
}
});
// what to do when progress changed (update the progress bar for example)
bw.ProgressChanged += new ProgressChangedEventHandler(
delegate(object o, ProgressChangedEventArgs args)
{
label1.Text = string.Format("{0}% Completed", args.ProgressPercentage);
});
// what to do when worker completes its task (notify the user)
bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(
delegate(object o, RunWorkerCompletedEventArgs args)
{
label1.Text = "Finished!";
});
bw.RunWorkerAsync();
}
Note:
I put everything in single method
using C#'s anonymous method for
simplicity but you can always pull
them out to different methods.
It is safe to update GUI within
ProgressChanged or
RunWorkerCompleted handlers.
However, updating GUI from DoWork
will cause
InvalidOperationException.
The ThreadPool.QueueUserWorkItem is pretty ideal for something simple. The only caveat is accessing a control from the other thread.
System.Threading.ThreadPool.QueueUserWorkItem(delegate {
DoSomethingThatDoesntInvolveAControl();
}, null);
Here is another option:
Task.Run(()=>{
//Here is a new thread
});
Quick and dirty, but it will work:
Using at top:
using System.Threading;
simple code:
static void Main( string[] args )
{
Thread t = new Thread( NewThread );
t.Start();
}
static void NewThread()
{
//code goes here
}
I just threw this into a new console application for an exmaple
Try using the BackgroundWorker class. You give it delegates for what to run, and to be notified when work has finished. There is an example on the MSDN page that I linked to.
If you want to get a value:
var someValue;
Thread thread = new Thread(delegate()
{
//Do somthing and set your value
someValue = "Hello World";
});
thread.Start();
while (thread.IsAlive)
Application.DoEvents();
Put that code in a function (the code that can't be executed on the same thread as the GUI), and to trigger that code's execution put the following.
Thread myThread= new Thread(nameOfFunction);
workerThread.Start();
Calling the start function on the thread object will cause the execution of your function call in a new thread.
Here how can use threads with a progressBar , its just for understing how the threads works, in the form there are three progressBar and 4 button:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
Thread t, t2, t3;
private void Form1_Load(object sender, EventArgs e)
{
CheckForIllegalCrossThreadCalls = false;
t = new Thread(birinicBar); //evry thread workes with a new progressBar
t2 = new Thread(ikinciBar);
t3 = new Thread(ucuncuBar);
}
public void birinicBar() //to make progressBar work
{
for (int i = 0; i < 100; i++) {
progressBar1.Value++;
Thread.Sleep(100); // this progressBar gonna work faster
}
}
public void ikinciBar()
{
for (int i = 0; i < 100; i++)
{
progressBar2.Value++;
Thread.Sleep(200);
}
}
public void ucuncuBar()
{
for (int i = 0; i < 100; i++)
{
progressBar3.Value++;
Thread.Sleep(300);
}
}
private void button1_Click(object sender, EventArgs e) //that button to start the threads
{
t.Start();
t2.Start(); t3.Start();
}
private void button4_Click(object sender, EventArgs e)//that button to stup the threads with the progressBar
{
t.Suspend();
t2.Suspend();
t3.Suspend();
}
private void button2_Click(object sender, EventArgs e)// that is for contuniue after stuping
{
t.Resume();
t2.Resume();
t3.Resume();
}
private void button3_Click(object sender, EventArgs e) // finally with that button you can remove all of the threads
{
t.Abort();
t2.Abort();
t3.Abort();
}
}
If you are going to use the raw Thread object then you need to set IsBackground to true at a minimum and you should also set the Threading Apartment model (probably STA).
public static void DoWork()
{
// do some work
}
public static void StartWorker()
{
Thread worker = new Thread(DoWork);
worker.IsBackground = true;
worker.SetApartmentState(System.Threading.ApartmentState.STA);
worker.Start()
}
I would recommend the BackgroundWorker class if you need UI interaction.
// following declaration of delegate ,,,
public delegate long GetEnergyUsageDelegate(DateTime lastRunTime,
DateTime procDateTime);
// following inside of some client method
GetEnergyUsageDelegate nrgDel = GetEnergyUsage;
IAsyncResult aR = nrgDel.BeginInvoke(lastRunTime, procDT, null, null);
while (!aR.IsCompleted) Thread.Sleep(500);
int usageCnt = nrgDel.EndInvoke(aR);
Charles your code(above) is not correct. You do not need to spin wait for completion. EndInvoke will block until the WaitHandle is signaled.
If you want to block until completion you simply need to
nrgDel.EndInvoke(nrgDel.BeginInvoke(lastRuntime,procDT,null,null));
or alternatively
ar.AsyncWaitHandle.WaitOne();
But what is the point of issuing anyc calls if you block? You might as well just use a synchronous call. A better bet would be to not block and pass in a lambda for cleanup:
nrgDel.BeginInvoke(lastRuntime,procDT,(ar)=> {ar.EndInvoke(ar);},null);
One thing to keep in mind is that you must call EndInvoke. A lot of people forget this and end up leaking the WaitHandle as most async implementations release the waithandle in EndInvoke.
another option, that uses delegates and the Thread Pool...
assuming 'GetEnergyUsage' is a method that takes a DateTime and another DateTime as input arguments, and returns an Int...
// following declaration of delegate ,,,
public delegate long GetEnergyUsageDelegate(DateTime lastRunTime,
DateTime procDateTime);
// following inside of some client method
GetEnergyUsageDelegate nrgDel = GetEnergyUsage;
IAsyncResult aR = nrgDel.BeginInvoke(lastRunTime, procDT, null, null);
while (!aR.IsCompleted) Thread.Sleep(500);
int usageCnt = nrgDel.EndInvoke(aR);
There are many ways of running separate threads in .Net, each has different behaviors. Do you need to continue running the thread after the GUI quits? Do you need to pass information between the thread and GUI? Does the thread need to update the GUI? Should the thread do one task then quit, or should it continue running? The answers to these questions will tell you which method to use.
There is a good async method article at the Code Project web site that describes the various methods and provides sample code.
Note this article was written before the async/await pattern and Task Parallel Library were introduced into .NET.
How to: Use a Background Thread to Search for Files
You have to be very carefull with access from other threads to GUI specific stuff (it is common for many GUI toolkits). If you want to update something in GUI from processing thread check this answer that I think is useful for WinForms. For WPF see this (it shows how to touch component in UpdateProgress() method so it will work from other threads, but actually I don't like it is not doing CheckAccess() before doing BeginInvoke through Dispathcer, see and search for CheckAccess in it)
Was looking .NET specific book on threading and found this one (free downloadable). See http://www.albahari.com/threading/ for more details about it.
I believe you will find what you need to launch execution as new thread in first 20 pages and it has many more (not sure about GUI specific snippets I mean strictly specific to threading). Would be glad to hear what community thinks about this work 'cause I'm reading this one. For now looked pretty neat for me (for showing .NET specific methods and types for threading). Also it covers .NET 2.0 (and not ancient 1.1) what I really appreciate.
I'd recommend looking at Jeff Richter's Power Threading Library and specifically the IAsyncEnumerator. Take a look at the video on Charlie Calvert's blog where Richter goes over it for a good overview.
Don't be put off by the name because it makes asynchronous programming tasks easier to code.

Categories

Resources