Update Status in ListView in C# - c#

I have a method that loops through all ListViewItems and for each one I am trying to simulate a delay with this code:
lvFiles.Items[i].SubItems.Add("In-Progress");
do
{
//loop
} while(DateTime.Now <= stopTime);
lvFiles.Items[i].SubItems[7].Text = "Complete";
The problem is that the form "freezes" for x seconds as expected but the status doesn't seem to update visually until all items get looped through... then all items get marked as "complete" all at once.
What is the problem, and how can I fix this?

Withim your loop try using:
Application.DoEvents();
Edit:
As per #sa_ddam213 correct comment, it is not good to invoke it in every iteration, so you could build a counter so that it is invoked every x iterations of the loop and not with every iteration.

If all you want to do is update the UI throughout the process then this would work:
lvFiles.BeginInvoke(() => lvFiles.Items[i].SubItems[7].Text = "Complete");

I ended up using a BackgroundWorker similar to this solution substituting with updating the listview instead of a progress bar:
private void bw_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
for (int i = 1; (i <= 10); i++)
{
if ((worker.CancellationPending == true))
{
e.Cancel = true;
break;
}
else
{
// Perform a time consuming operation and report progress.
System.Threading.Thread.Sleep(500);
worker.ReportProgress((i * 10), "some data to pass to other thread");
}
}
}
and
private void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
//listview update code here - e.Argument cast and parsed to update listview
}

Related

How to change TextBlock.Text every loop?

This is UWP C# application. I want to display the i variable.
private void btn2_Click(object sender, RoutedEventArgs e)
{
for(int i = 0; i<=10000000; i++)
{
textBlock2.Text = i.ToString();
}
}
But after I clicked the button, the text only change one time after the loop is finished.
How can see changing text in every loop?
Actually, your UI is frozen while the long loop is executing, so nothing can be updated on the screen. Try this
private async void btn2_Click(object sender, RoutedEventArgs e)
{
for(int i = 0; i<=10000000; i++)
{
textBlock2.Text = i.ToString();
await Task.Delay(200); //stay 200 ms before showing next number so human eyes can see it.
}
}
When it executes to this line await Task.Delay(200);, the loop is temporarily suspended - for 200 milliseconds, and the UI thread now has a chance to process the drawing tasks pending in the queue, which includes redrawing the textblock.

How to tell when a progressbar is done?

I am using C# with WinForms. I am updating a progressBar. When the Value reaches it's maximum value, I would like it to display a messageBox.
Is there anyway for the progressBar to execute a method when it's full? Is so then some code sample or a link to the solution would be appreciated
private void BackgroundWorkerProgressChanged(object sender, ProgressChangedEventArgs e)
{
//throw new NotImplementedException();
}
private void bgWorker_DoWork(object sender, DoWorkEventArgs e)
{
}
// Back on the 'UI' thread so we can update the progress bar - and our label :)
void bgWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
// The progress percentage is a property of e
int percentComplete = progressBarStatus.Value / progressBarStatus.Maximum;
labelPercentComplete.Text = percentComplete.ToString() + "% Completed";
//progressBarStatus.Value = e.ProgressPercentage;
//labelPercentComplete.Text = String.Format("Trade{0}", e.ProgressPercentage);
}
private void bgWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if(progressBarStatus.Value == progressBarStatus.Maximum)
{
MessageBox.Show("Test");
}
}
public void Form1_Load(object sender, EventArgs e)
{
backgroundWorker1.DoWork += new DoWorkEventHandler(bgWorker_DoWork);
backgroundWorker1.RunWorkerCompleted += new RunWorkerCompletedEventHandler
(bgWorker_RunWorkerCompleted);
backgroundWorker1.ProgressChanged += BackgroundWorkerProgressChanged;
}
It appears that you do not want to do something when background worker completes, but you want to do something when progress bar reaches maximum... Ok, first, set your progressBarStatus maximum value, then you should try something like this:
void bgWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
if (progressBarStatus.Maximum == e.ProgressPercentage)
{
// do whatever you want to do
}
}
and update progressBarStatus value from from another form.
Altough this may not the best way to do things, if this is really what you want, then do whatever makes you happy... :)
EDIT:
Ok, I added complete example of the program that works perfectly, with calling ProgressChanged event, and checking for the Maximum value correctly, when the Maximum value is reached, ProgressBar is getting restarted and the message is printed in the Output window, with bunch of comments (and bunch of typos of course :D ), please try this example, see how it works, and apply it to your problem.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Windows.Forms;
namespace BGWORKERAPP
{
public partial class Form1 : Form
{
BackgroundWorker bgWorker = new BackgroundWorker();
public Form1()
{
InitializeComponent();
bgWorker.DoWork += bw_DoWork;
bgWorker.WorkerReportsProgress = true; // needed to be able to report progress
bgWorker.WorkerSupportsCancellation = true; // needed to be able to stop the thread using CancelAsync();
bgWorker.ProgressChanged += bw_ProgressChanged;
bgWorker.RunWorkerCompleted += bw_RunWorkerCompleted;
// ProgressBar is added to the form manually, and here I am just setting some initial values
progressBarStatus.Maximum = 100;
progressBarStatus.Minimum = 0;
progressBarStatus.Value = 0;
progressBarStatus.Step = 10;
}
void bw_DoWork(object sender, DoWorkEventArgs e)
{
int i = 0;
while (true) // keep looping until user presses the "Stop" button
{
if (bgWorker.CancellationPending) // if bgWorker.CancelAsync() is called, this CancelationPending token will be set,
{ // and if statement will be true
bgWorker.CancelAsync();
return; // Thread is getting canceled, RunWorkerCompleted will be called next
}
i++; // add any value you want, I chose this value because of the test example...
Thread.Sleep(1); // give thread some time to report (1ms is enough for this example) - NECESSARY,
//WITHOUT THIS LINE, THE MAIN THREAD WILL BE BLOCKED!
bgWorker.ReportProgress(i); // report progress (will call bw_ProgressChanged) - NECESSARY TO REPORT PROGRESS!
}
}
int somethingTerrible = 1; // used to do something terrible ;)
void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
// I added this "somethingTerrible" variable to make the ProgressChanged run all over again, even when e.ProgressPercentage value
// is greater then the progressBarStatus.Maximum, but, you should call bw.CancelAsync() because the job should be finished.
// Also, this code will give you Exception eventually, numbers are limited after all...
if (somethingTerrible * progressBarStatus.Maximum == e.ProgressPercentage)
{
Debug.WriteLine("THIS IS CALLED WHEN THE MAXIMUM IS REACHED"); // this will be printed in the Output window
progressBarStatus.Value = 0; // progressBarStatus value is at the maximum, restart it (or Exception will be thrown)
//bw.CancelAsync(); // used to stop the thread when e.ProgressPercentage is equal to progressBarMaximum, but in our
// example, we just make the code keep running.
// We should cancel bgWorker now because the work is completed and e.ProgressPercentage will
// be greater then the value of the progressBarStatus.Maximum, but if you really want
// you can do something like this to make the thread keep reporting without any errors (until numbers reach the limit)...
somethingTerrible++;
}
else
{
progressBarStatus.Value++; // increasing progressBarStatus.Value, until we get to the maximum.
}
}
void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
MessageBox.Show("Worker completed"); // worker finished the task...
}
// Buttons are added to the Form manually as well
private void runBgTask_Click(object sender, EventArgs e) // button on the Form to start the thread
{
bgWorker.RunWorkerAsync(); // start the background worker (call DoWork)
}
private void stopBgTask_Click(object sender, EventArgs e) // button on the Form to stop the thread
{
bgWorker.CancelAsync(); // tell the background worker to stop (will NOT stop the thread immediately); the DoWork will be
// called once again, but with CancelationPending token set to true, so the if statement
// in the DoWork will be true and the thread will stop.
}
}
}
I guess you should look at BackgroundWorker which is made specifically for this purpose. You will get Event RunWorkerCompleted when your work in finished. I am giving you a working example where you are copying lots of files.
BackgroundWorker bgWorker = new BackgroundWorker();
bgWorker.DoWork += BackgroundWorkerDoWork;
bgWorker.ProgressChanged += BackgroundWorkerProgressChanged;
bgWorker.RunWorkerCompleted += new BackgroundWorkerCompletedEventHandler
(bgWorker_RunWorkerCompleted);
void StartWork()
{
// Start BackGround Worker Thread
bgWorker.RunWorkerAsync();
}
void BackgroundWorkerDoWork(object sender, DoWorkEventArgs e)
{
//NOTE : DONT play with the UI thread here...
// Do Whatever work you are doing and for which you need to show progress bar
CopyLotsOfFiles() // This is the function which is being run in the background
e.Result = true;// Tell that you are done
}
void CopyLotsOfFiles()
{
Int32 counter = 0;
List<String> filestobeCopiedList = ...; // get List of files to be copied
foreach (var file in filestobeCopiedList)
{
counter++;
// Calculate percentage for Progress Bar
Int32 percentage = (counter * 100) / filesCount;
bgWorker.ReportProgress(percentage);
// Files copy code goes here
}
bgWorker.ReportProgress(100);
}
void BackgroundWorkerProgressChanged(object sender, ProgressChangedEventArgs e)
{
// Access Main UI Thread here
progressBar1.Value = e.ProgressPercentage;
}
private void BackgroundWorkerCompletedEventHandler(object sender, RunWorkerCompletedEventArgs e)
{
//Always check e.Cancelled and e.Error before checking e.Result!
//even though I'm skipping that here
var operationSuccessFul = Convert.ToBoolean(e.Result);
if(operationSuccessFul)
MessageBox.Show("I am Done");
}
You will get a call in BackgroundWorkerCompletedEventHandler function when you are done. You should display your progress bar in BackgroundWorkerProgressChanged event handler
You should think the other way round: Create a central "Progress class". This class is responsible for:
Update the progress bar
Show a MessageBox if certain conditions are met
Or to put it another way: its not the responibility of the progressbar to ... do something else than showing progress.

C# Progressbar filling while method is working

Im building a little app which has a long loading time.
I want to display this loading time in a progressbar to see how long i have to wait till the programm is loaded.
I hope you understand what i want..
I tried the backgroundworker already but dont understand how to use it, in every example they use in the DoWork Event a simple
for (int i = 0; i < 100; i++)
{
//method etc here
backgroundWorker.ReportProgress(i);
}
But in my eyes this is senseless for me because this only repeats my method...
Thank you in advance!
EDIT:
private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
Aktie dataAktie = new Aktie(aktien_name);
for (int i = 0; i < 100; i++)
{
dataAktie.ReadFromDatabase();
dataAktie.FetchData();
backgroundWorker.ReportProgress(i);
}
}
private void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
progressBar1.Value = e.ProgressPercentage;
}
private void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
//Controls that have to be filled
}
But this Controls dont get data im veryyyyy confused
The following code example demonstrates the use of the ReportProgress method to report the progress of an asynchronous operation to the user.
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
// This method will run on a thread other than the UI thread.
// Be sure not to manipulate any Windows Forms controls created
// on the UI thread from this method.
backgroundWorker.ReportProgress(0, "Working...");
Decimal lastlast = 0;
Decimal last = 1;
Decimal current;
if (requestedCount >= 1)
{ AppendNumber(0); }
if (requestedCount >= 2)
{ AppendNumber(1); }
for (int i = 2; i < requestedCount; ++i)
{
// Calculate the number.
checked { current = lastlast + last; }
// Introduce some delay to simulate a more complicated calculation.
System.Threading.Thread.Sleep(100);
AppendNumber(current);
backgroundWorker.ReportProgress((100 * i) / requestedCount, "Working...");
// Get ready for the next iteration.
lastlast = last;
last = current;
}
backgroundWorker.ReportProgress(100, "Complete!");
}
** http://msdn.microsoft.com/en-us/library/a3zbdb1t%28v=vs.110%29.aspx
A BackgroundWorker and it's ReportProgress method are no magic wanda that simply shows you any progress you want, you actually have to change your code to do so.
The DoWork event handler should contain the code you want to execute in the background. Ideally this is something for progress can be measured easily. For example if you have to process 10 items then after each item you could say I'm now 10% further done. That's why the example code contains a for loop.
Your code only contains two method calls, ReadFromDatabase and FetchData. So you could simply do
dataAktie.ReadFromDatabase();
backgroundWorker.ReportProgress(50); // 50% done
dataAktie.FetchData();
backgroundWorker.ReportProgress(100); // 100% done
Obviously that not really perfect. The only way to have more accurate progress is to change the ReadFromDatabase and FetchData methods, for example let them take the BackgroundWorker object as a parameter so that they can also report progress, or provide a callback for that.

c# Make a delayer but still be able to have form open

and on my c# program whenever i try:
System.Threading.Thread.Sleep(#);
as in delay number
It works, but whenever its "delaying" (i guess that's what its called) I can't get my form to pop up on my screen from the task bar, almost like reopening it (?). Could somebody help me make a thread that doesn't "freeze" the form? Thanks!
So, yeah, I have already tried
System.Threading.Thread.Sleep(#);
But that just freezes the form :/ thank you
oh btw, this is c#
You can use a Timer to delay a operation.
Example:
Timer timer = new Timer(10000);
timer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
timer.Start();
After 10000 MS the following Method will be called:
private static void OnTimedEvent(object source, ElapsedEventArgs e)
{
//DoSomething
}
Sounds like you're after a background worker. This will allow you to keep your main form up but do some time consuming processing on another thread. Since you didn't post any specific code for your issue, I'm pasting in a snippet from a larger example found on MSDN
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
for (int i = 1; i <= 10; i++)
{
if (worker.CancellationPending == true)
{
e.Cancel = true;
break;
}
else
{
// Perform a time consuming operation and report progress.
System.Threading.Thread.Sleep(500);
worker.ReportProgress(i * 10);
}
}
}

C# backgroundWorker reports string?

How can I report a string (like "now searching file. . .", "found selection. . .") back to my windows.form from a backgroundWorker as well as a percentage. Additionally, I have a large class that contains the method I want to run in the backgroundWorker_Work. I can call it by Class_method(); but i am then unable to report my percentage done or anything from the called class, only from the backgroundWorker_Work method.
Thanks!
I'm assuming WCF also have the method
public void ReportProgress(int percentProgress, Object userState);
So just use the userState to report the string.
private void worker_DoWork(object sender, DoWorkEventArgs e)
{
//report some progress
e.ReportProgress(0,"Initiating countdown");
// initate the countdown.
}
And you'll get that "Initiating countdown" string back in ProgressChanged event
private void worker_ProgressChanged(object sender,ProgressChangedEventArgs e)
{
statusLabel.Text = e.UserState as String;
}
You can use the userState parameter of ReportProgress method to report that strings.
Here's an example from MSDN:
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
// This method will run on a thread other than the UI thread.
// Be sure not to manipulate any Windows Forms controls created
// on the UI thread from this method.
backgroundWorker.ReportProgress(0, "Working...");
Decimal lastlast = 0;
Decimal last = 1;
Decimal current;
if (requestedCount >= 1)
{ AppendNumber(0); }
if (requestedCount >= 2)
{ AppendNumber(1); }
for (int i = 2; i < requestedCount; ++i)
{
// Calculate the number.
checked { current = lastlast + last; }
// Introduce some delay to simulate a more complicated calculation.
System.Threading.Thread.Sleep(100);
AppendNumber(current);
backgroundWorker.ReportProgress((100 * i) / requestedCount, "Working...");
// Get ready for the next iteration.
lastlast = last;
last = current;
}
backgroundWorker.ReportProgress(100, "Complete!");
}
Read Simple Multi-threading in Windows Forms.
It's a 3-part series.
use a delegate.

Categories

Resources