I want to refresh a progess bar in C# WPF.
This question sounds very easy and i should be able to google it. But the solutions I have seen unsatisfy me.
Assuming that i have to run a very long algorithm with e.g. 5 different steps.
I don't know exactly how long it will take to calculate the different steps.
But i know what i have programmed an i could use a profiler to check how much time the CPU uses for each step (in % of the total time for all steps).
This could be the times e.g.:
Method1() takes 3s
Method2() takes 5s
Method3() takes 1s
This are my approaches:
The "Easy" Approach:
ProgressBar pb = new ProgressBar()
{
// The total duration of all methods
Maximum = 9
};
Method1();
// + 3 for 3 seconds
pb.Value += TimeForMethod1;
Method2();
// + 5 for 5 seconds
pb.Value += TimeForMethod2;
Method3();
// + 1 for 1 second
pb.Value += TimeForMethod3;
This is pretty easy. But has a problem. This blocks my UI thread for 9 seconds wich is horrible (because the user could think the programm has crashed).
So it seems obvious to use a thread..
The "Thread" Approach:
This has the problem that I need to dispach every operation on the ProgressBar which could be very slow (for very much updates on the ProgressBar)
I have written a "TaskQueue" for that. I can save all work I want to do in a Queue and a Thread is working all these Task after Run is called and updates the ProgressBar (and a Label) between the Tasks.
I don't want to post all the code of the ThreadQueue, because it is very much and maybe not that good implemented (yet).
This is the important part of the thread method:
foreach (var threadQueueNode in threadQueue)
{
// Changes e.g. a label displaying what the thread is doing next
threadQueueNode.PreMainFunction.Invoke();
// Executes the main task
this.Result = threadQueueNode.MainFunction.Invoke();
// Updates the ProgressBar after the work is done.
threadQueueNode.PostMainFunction.Invoke();
}
PostMainFunction is a Delegate and e.g. this:
PostMainFunction = (Action<int>)((value) => this.Dispatcher.Invoke(() => this.ProgressBarStatus.Value += value));
Wich is the professional way to update a ProgessBar for a problem like mine?
I'd be happy about a discussion.
Thanks for your help and your time!
BackgroundWorker is clean and legible:
var bw = new BackgroundWorker();
bw.DoWork += (s, e) =>
{
var worker = s as BackgroundWorker;
Method1();
worker.ReportProgress(30);
Method2();
worker.ReportProgress(80);
Method3();
worker.ReportProgress(100);
};
bw.ProgressChanged += (s, e) =>
{
pb.Value += e.ProgressPercentage;
};
bw.RunWorkerCompleted += (s, e) =>
{
};
bw.RunWorkerAsync();
This has the problem that I need to dispach every operation on the ProgressBar which could be very slow
The solution is to precompute the changes to the progressbar and only invoke the UI thread and update the graphics when needed.
For example, you have 100.000 operations. You do not need to update the progress bar 100.000 times. The user will not notice the difference anyway. Update once for each percent (1000 records in this case) so the user will be notified on each percent. Updating the UI every few seconds is fine.
Related
What I am trying to achieve is to add text after every operation to a RichTextBox.
The problem is, that these operations take some time and instead of viewing the appended text after every operation finishes, I view them all at the end of the routine.
Semi-Pseudo code:
RichTextBox richTextBox = new RichTextBox()
if (Operation1())
{
richTextBox.AppendText("Operation1 finished");
if (Operation2())
{
richTextBox.AppendText("Operation2 finished");
if (Operation3())
{
richTextBox.AppendText("Operation3 finished");
}
}
}
The problem is that I view the appended text of operation 1 & 2 after the operation 3 is finished.
I read somewhere that I need to use something called BackgroundWorker???
Using BackgroundWorker, you would just put the background work into DoWork, and the update into RunWorkerCompleted:
var bw1 = new BackgroundWorker();
var bw2 = new BackgroundWorker();
var bw3 = new BackgroundWorker();
bw1.DoWork += (sender, args) => args.Result = Operation1();
bw2.DoWork += (sender, args) => args.Result = Operation2();
bw3.DoWork += (sender, args) => args.Result = Operation2();
bw1.RunWorkerCompleted += (sender, args) => {
if ((bool)args.Result)
{
richTextBox.AppendText("Operation1 ended\n");
bw2.RunWorkerAsync();
}
};
bw2.RunWorkerCompleted += (sender, args) => {
if ((bool)args.Result)
{
richTextBox.AppendText("Operation2 ended\n");
bw3.RunWorkerAsync();
}
};
bw3.RunWorkerCompleted += (sender, args) => {
if ((bool)args.Result)
{
richTextBox.AppendText("Operation3 ended\n");
}
};
bw1.RunWorkerAsync();
You'll notice that this runs afoul of "DRY". You could always consider abstracting the tasks for each step using something like:
var operations = new Func<bool>[] { Operation1, Operation2, Operation3, };
var workers = new BackgroundWorker[operations.Length];
for (int i = 0; i < operations.Length; i++)
{
int locali = i; // avoid modified closure
var bw = new BackgroundWorker();
bw.DoWork += (sender, args) => args.Result = operations[locali]();
bw.RunWorkerCompleted += (sender, args) =>
{
txt.Text = string.Format("Operation{0} ended\n", locali+1);
if (locali < operations.Length - 1)
workers[locali + 1].RunWorkerAsync();
};
workers[locali] = bw;
}
workers[0].RunWorkerAsync();
You could do the above 3 times, or use ReportProgress to run all tasks in one background thread, and periodically report progress.
The way that WPF (and most other UI frameworks work) is that there is a UI thread, which handles all the UI events (such as button clicking) and UI drawing.
The UI can't draw things if it's busy doing other things. What's happening is this:
You click a button
The UI thread gets a button click message, and invokes your click handler function
Now, the UI can't redraw or perform any other updates until your click handler function finishes.
Your Operation1 function finishes, and you append to the RichTextBox
The UI can't update because it's still stuck running your code
Your Operation2 function finishes, and you append to the RichTextBox
The UI can't update because it's still stuck running your code
Your Operation3 function finishes, and you append to the RichTextBox
Your function finishes, and now the UI thread is free, and it can finally process the updates and redraw itself.
This is why you see a pause and then all 3 updates together.
What you need to do is make the code that takes a long time run on a different thread so that the UI thread can remain free to redraw and update when you'd like it to. This sample program works for me - it requires .NET 4.5 to compile and run
using System.Threading.Tasks;
...
// note we need to declare the method async as well
public async void Button1_Click(object sender, EventArgs args)
{
if (await Task.Run(new Func<bool>(Operation1)))
{
richTextBox.AppendText("Operation1 finished");
if (await Task.Run(new Func<bool>(Operation2)))
{
richTextBox.AppendText("Operation2 finished");
if (await Task.Run(new Func<bool>(Operation3)))
{
richTextBox.AppendText("Operation3 finished");
}
}
}
}
What happens here is that we use the C# magical async feature, and the order of operations goes like this:
You click a button
The UI thread gets a button click message, and invokes your click handler function
Instead of calling Operation1 directly, we pass it to Task.Run. This helper function will run your Operation1 method on a thread pool thread.
We use the magic await keyword to wait for the thread pool to finish executing operation1. What this does behind the scenes is something morally equivalent to this:
suspend the current function - and thus free up the UI thread to re-draw itself
resume when the thing we're waiting for completes
Because we're running the long operations in the thread pool now, the UI thread can draw it's updates when it wants to, and you'll see the messages get added as you'd expect.
There are some potential drawbacks to this though:
Because your Operation1 method is Not running on the UI thread, if it needs to access any UI related data (for example, if it wants to read some text from a textbox, etc), it can no longer do this. You have to do all the UI stuff first, and pass it as a parameter to the Operation1 method
It's generally not a good idea to put things that take a long time (more than say 100ms) into the thread pool, as the thread pool can be used for other things (like network operations, etc) and often needs to have some free capacity for this. If your app is just a simple GUI app though, this is unlikely to affect you.
If it is a problem for you, you can use the await Task.Factory.StartNew<bool>(_ => Operation1(), null, TaskCreationOptions.LongRunning))) instead and each task will run in it's own thread and not use the thread pool any more. It's a bit uglier though :-)
I had a SQL Stored Procedure that get a mbd file and import it using itself in less than 3 second but because of the security of the shared server I can't do it anymore but instead I can use vb.net to import necessary temp tables to Sql server and continue the process Unfortunately it gets so long to complete the process (about 3 minutes for a 3MegaByte mdb file), and I need to show client the process so the client can wait patiently and know how far the process has gone.
I have seen many things related to this but they are all showing an image loading instead of exact progress bar,My question is: Is there any possible way to show the progress bar while based on how the process is doing?
PS: I can place the show progress percent in my for loop in vb.net.
EDIT: To be specific I just need to know how can I show the client the progress and just update the progress bar in html or maybe change the progress bar width style?
Thanks
You can use a BackGroundWorker:
When using backgroundWorker, it is always convenient for me to use #Keith template
BackgroundWorker bw = new BackgroundWorker { WorkerReportsProgress = true };
bw.DoWork += (sender, e) =>
{
//what happens here must not touch the form
//as it's in a different thread
//Here you should call the function that does the heavy, slow work.
//pass the BackgroundWorker instance (bw) as an argument
};
bw.ProgressChanged += ( sender, e ) =>
{
//update progress bars here
};
bw.RunWorkerCompleted += (sender, e) =>
{
//now you're back in the UI thread you can update the form
//remember to dispose of bw now
};
worker.RunWorkerAsync();
In you function update about the progress by using something like:
void YourFunction(BackgroundWorker bw)
{
for (int i = 0; i < length; i++)
{
//do your work
int percent = (i / length) * 100;
bw.ReportProgress(percent);
}
}
I'm building a program that has 5 total forms. 1 MDIContainer and 4 MDIChildren.
I currently have a thread.sleep(1000) for each MDIChild. When the operation is performed, I still need the other 3 MDIChilds to be working and interactable. However, right now when the thread.sleep(1000) is called, the entire program sleeps for 1 second and I have to wait for the sleep to finish before interacting with any other form.
Is there a way to make a single form sleep? If so, how and example please.
You should basically never be sleeping in the UI thread...ever...for exactly the reason your question demonstrates.
You just want to execute some code in 1 second. There are two effective ways at doing this:
1) You can use a Timer. By using the timer in the Forms namespace you can ensure that it's Tick event fires in the UI thread, and you don't need to do anything special to interact with UI elements.
private void Form1_Load(object sender, EventArgs e)
{
label1.Text = "Loading . . .";
var timer = new System.Windows.Forms.Timer();
timer.Interval = 1000;
timer.Tick += (s, args) =>
{
label1.Text = "Done!";
};
timer.Start();
}
As you can see, this does take a bit more code than is ideal, but it still works.
2) If you have .NET 4.5 and C# 5.0 you can use tasks with await to make this really slick and easy:
private async void Form1_Load(object sender, EventArgs e)
{
label1.Text = "Loading . . .";
await Task.Delay(1000); //wait 1 second, but don't block the UI thread.
label1.Text = "Done!";
}
I need a logic that would allow me to do something when a thread is running for more that X amount of seconds.
Like in this incredibly ugly example, here it will check every second and if the workerThread is running for 10 or more minutes it shows a message...
var timeWorking = TimeSpan.FromMinutes(0);
workerThread = new Thread(RunTask);
workerThread.Start(task);
while (workerThread.IsAlive)
{
Thread.Sleep(TimeSpan.FromSeconds(1));
timeWorking = timeWorking.Add(TimeSpan.FromSeconds(1));
if (timeWorking.TotalMinutes < 10) continue;
timeWorking = TimeSpan.FromMinutes(0);
Console.Writeline("Here we go... the event")
}
Please help me to make it right...
What should I use Diagnostics.StopWatch, System.Timers.Timer or Threading.Timer ?
UPD: All the answers confused me even more...
The task is to check if workerThread is running for more than X amount of time, and if it is, call some method, reset the timer and check again if workerThread now is running for more than X amount of time since the last time we called the method... and so on and on...
UPD2: Basically I have a thread that does a processing based on information pulled from AmazonSQS queue. SQS Queue message has a visibility timeout. If the task will take longer than default visibility timeout - the message will be back to the queue before the task has finished. And then it will be picked up by another machine. To avoid that I need to extend visibility timeout of SQS message.
So I can do that by checking periodically if thread stil isALive then I can add couple of minutes to the message visibility timeout. After a minute and 50 seconds or so, I should check again and if thread still isALive then add couple more minutes and so on.
Since you know that the thread needs to do something after ten minutes, why not simply use an interval on the timer like this:
var interval = 1000 * 60 * 10; // ten minutes
var timer = new System.Timers.Timer(interval) { AutoReset = false };
timer.Elapsed += ((sender, eventArgs) =>
{
// Do your work here...
});
workerThread = new Thread(RunTask);
workerThread.Start(task);
timer.Start();
This way you are not checking each second and you will execute your code after a desired amount of time.
I think System.Timers.Timer is better suited based on what you've described. But, it depends. If you want to do something with the UI with the timer. Forms.Timer is better.
In either case, you could simply check if the thread is still alive when the timer Elapsed (or Ticked) and do something if it is.
e.g.
timeThreadStarted = DateTime.Now;
workerThread = new Thread(RunTask);
System.Timers.Timer timer = new System.Timers.Timer(TimeSpan.FromSeconds(1).TotalMilliseconds);
timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed);
workerThread.Start(task);
//...
static void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
if(workerThread != null && workerThread.IsAlive)
{
Console.WriteLine("thread has been running for {0}!", DateTime.Now - timeThreadStarted);
}
}
This checks the thread state after 1 second. If it is still Alive then it has been running for at least one second.
This has the benefit of not blocking any threads. If you have a UI and you want to do this, then you can't block the UI Thread (it will become unresponsive and provide a poor user experience).
You could also do Thread.Join with a TimeSpan like the example at http://msdn.microsoft.com/en-us/library/23f7b1ct.aspx so that you don't have to do a Thread.Sleep.
Note: either approach blocks calling thread until the time has elapsed. Not suitable for main/UI threads.
You can use a Timer that will raise an event once the elapsed time as triggered.
private static void Main(string[] args)
{
var thread = new Thread(
() =>
{
var timer = new System.Timers.Timer
{
Interval = 10000, //10s
AutoReset = false, //only raise the elapsed event once
};
timer.Elapsed += timer_Elapsed;
timer.Start();
while (true)
{
Console.WriteLine("Running...");
Thread.Sleep(1000); //Always put a thread to sleep when its blocking so it does not waste CPU cycles.
}
});
thread.Start();
}
private static void timer_Elapsed(object sender, ElapsedEventArgs e)
{
//thread is running for more that X (10s) amount of seconds
Console.WriteLine("Timer elapsed");
}
That is a simple example. In this example, the thread never exits. But you can add your own logic where necessary to get what you are trying to accomplish.
Short answer: Yes, use System.Timers.Timer
You can use the Task wait method, for example
var t = Task.Factory.StartNew(() => MyAction()); // MyAction is an action to be executed in parallel
bool check = t.Wait(10000); //wait for 10000 milliseconds
if (check)
{
// all ok
}
else
{
// over time
}
The Wait method blocks until the task ends or timeout happens. If you don't want to block your primary thread, you can run the example code using another task that works in parallel and checks the working task.
I created a windows service, that is supposed to check a certain table in the db for new rows every 60 seconds. For every new row that was added, I need to do some heavy processing on the server that could sometimes take more than 60 seconds.
I created a Timer object in my service, that ticks every 60 seconds and invokes the wanted method.
Since I don't want this timer to tick while processing the new lines found, I wrapped the method in a lock { } block, so this won't be accessible by another thread.
It looks something like this :
Timer serviceTimer = new Timer();
serviceTimer.Interval = 60;
serviceTimer.Elapsed += new ElapsedEventHandler(serviceTimer_Elapsed);
serviceTimer.Start();
void serviceTimer_Elapsed(object sender, ElapsedEventArgs e)
{
lock (this)
{
// do some heavy processing...
}
}
Now, I'm wondering -
If my timer ticks, and finds a lot of new rows on the db, and now the processing will take more than 60 seconds, the next tick won't do any processing till the previous one finished. This is the effect I want.
But now, will the serviceTimer_Elapsed method go off immediatly once the first processing was finished, or will it wait for the timer to tick again.
What I want to happen is - if the processing requires more than 60 seconds, than the timer will notice the thread is locked, and wait another 60 seconds to check again so I will never get stuck in a situation where there are a queue of threads waiting for the previous one to finish.
How can i accomplish this result ?
What is the best practice for doing this ?
Thanks!
You might try disabling the timer during processing, something like
// Just in case someone wants to inherit your class and lock it as well ...
private static object _padlock = new object();
try
{
serviceTimer.Stop();
lock (_padlock)
{
// do some heavy processing...
}
}
finally
{
serviceTimer.Start();
}
Edit : OP didn't specify whether the reentrancy was caused only by the timer or whether the service was multi threaded. Have assumed the later, but if the former then locking should be unnecessary if the timer is stopped (AutoReset or manually)
You don't need the lock in this case. Set timer.AutoReset=false before starting it.
Restart the timer in the handler after you are done with your processing. This will ensure that the timer fires 60 seconds after each task.
A similar variation on other answers, that allows the timer to keep ticking and only do the work when the lock can be obtained, instead of stopping the timer.
Put this in the elapsed event handler:
if (Monitor.TryEnter(locker)
{
try
{
// Do your work here.
}
finally
{
Monitor.Exit(locker);
}
}
Put a quick check it see if the service is running. if it is running it will skip this event and wait for the next one to fire.
Timer serviceTimer = new Timer();
serviceTimer.Interval = 60;
serviceTimer.Elapsed += new ElapsedEventHandler(serviceTimer_Elapsed);
serviceTimer.Start();
bool isRunning = false;
void serviceTimer_Elapsed(object sender, ElapsedEventArgs e)
{
lock (this)
{
if(isRunning)
return;
isRunning = true;
}
try
{
// do some heavy processing...
}
finally
{
isRunning = false;
}
}
I recommend you don't let the timer tick at all while its processing.
Set the Timers AutoReset to false. And start it at the end. Here's a full answer you might be interested in
Needed: A Windows Service That Executes Jobs from a Job Queue in a DB; Wanted: Example Code
Other options might be to use a BackGroundWorker class, or TheadPool.QueueUserWorkItem.
Background worker would easily give you the option check for current processing still occurring and process 1 item at a time. The ThreadPool will give you the ability to continue queueing items every tick (if necessary) to background threads.
From your description, I assume you are checking for items in a queue in a database. In this case, I would use the ThreadPool to push the work to the background, and not slow/stop your checking mechanism.
For a Service, I would really suggest you look at using the ThreadPool approach. This way, you can check for new items every 60 seconds with your timer, then Queue them up, and let .Net figure out how much to allocate to each item, and just keep pushing the items into the queue.
For Example: If you just use a timer and you have 5 new rows, which require 65 seconds of processing time total. Using the ThreadPool approach, this would be done in 65 seconds, with 5 background work items. Using the Timer approach, this will take 4+ minutes (the minute you will wait between each row), plus this may cause a back-log of other work that is queueing up.
Here is an example of how this should be done:
Timer serviceTimer = new Timer();
void startTimer()
{
serviceTimer.Interval = 60;
serviceTimer.Elapsed += new ElapsedEventHandler(serviceTimer_Elapsed);
serviceTimer.AutoReset = false;
serviceTimer.Start();
}
void serviceTimer_Elapsed(object sender, ElapsedEventArgs e)
{
try
{
// Get your rows of queued work requests
// Now Push Each Row to Background Thread Processing
foreach (Row aRow in RowsOfRequests)
{
ThreadPool.QueueUserWorkItem(
new WaitCallback(longWorkingCode),
aRow);
}
}
finally
{
// Wait Another 60 Seconds and check again
serviceTimer.Stop();
}
}
void longWorkingCode(object workObject)
{
Row workRow = workObject as Row;
if (workRow == null)
return;
// Do your Long work here on workRow
}
There's quite a neat way of solving this with Reactive Extensions. Here's the code, and you can read a fuller explanation here: http://www.zerobugbuild.com/?p=259
public static IDisposable ScheduleRecurringAction(
this IScheduler scheduler,
TimeSpan interval,
Action action)
{
return scheduler.Schedule(
interval, scheduleNext =>
{
action();
scheduleNext(interval);
});
}
And you could use it like this:
TimeSpan interval = TimeSpan.FromSeconds(5);
Action work = () => Console.WriteLine("Doing some work...");
var schedule = Scheduler.Default.ScheduleRecurringAction(interval, work);
Console.WriteLine("Press return to stop.");
Console.ReadLine();
schedule.Dispose();
another posibility would be something like this:
void serviceTimer_Elapsed(object sender, ElapsedEventArgs e)
{
if (System.Threading.Monitor.IsLocked(yourLockingObject))
return;
else
lock (yourLockingObject)
// your logic
;
}