" int ans = 2;
private void Form1_Load(object sender, EventArgs e)
{
for (int i = 0; i <21; i++)
{
ans = 2;
label1.Text += i.ToString();
while (true)
{
if (ans == 1)
{
break;
}
}
}
}
private void button1_Click(object sender, EventArgs e)
{
ans = 1;
} "
this is a simple app
I want to print a number & then wait to the button to be clicked to break the while loop
but when I run the application , the form doesn't show .
"T think that the problem is the while (true)".
what to do?
Use a timer. Start the timer when the form loads. Each time it ticks, increment the number and display it. On button click, you just need to stop the timer.
private Timer _myTimer;
private int number = 0;
private void Form1_Load(object sender, EventArgs e)
{
_myTimer = new Timer();
_myTimer.Interval = 1; // 1 millisecond
_myTimer.Tick += new EventHandler(MyTimer_Tick);
_myTimer.Start();
}
// increments the number at timer tick
private void MyTimer_Tick(object sender, EventArgs e)
{
number ++;
// TODO: update UI here
}
// Stops the timer
private void button1_Click(object sender, EventArgs e)
{
_myTimer.Stop();
}
It's best to not use a loop here. Since this loop won't end you won't ever leave Form_Load and it won't display the form. If you were trying to do some task when the user clicks a button, why not move that logic to button1_Click?
The correct way to implement such a task as you describe would be as such:
private EventWaitHandle ewh = new EventWaitHandle(false, EventResetMode.AutoReset);
private void Form1_Load(object sender, EventArgs e)
{
Task.Factory.StartNew(() =>
{
for (int i = 0; i < 26; i++)
{
ewh.WaitOne();
Action updateLable = () => label1.Text = "" + i;
label1.BeginInvoke(updateLable);
}
});
}
private void button1_Click(object sender, EventArgs e)
{
ewh.Set();
}
As you can see I've replaced your busy wait (while(true)) with a .Net wait handle.
One of the answers describes a timer that acts every millisecond - that is a busy wait of sorts.
This is what async/await is for. Mark your Load() event with "async", then "await" a Task that continues when a ManualResetEvent is triggered in the Button click handler:
private System.Threading.ManualResetEvent mre = new System.Threading.ManualResetEvent(false);
private async void Form1_Load(object sender, EventArgs e)
{
for (int i = 0; i < 21; i++)
{
label1.Text = i.ToString();
mre.Reset();
await Task.Factory.StartNew(() => { mre.WaitOne(); });
}
button1.Enabled = false;
label1.Text = "Done!";
}
private void button1_Click(object sender, EventArgs e)
{
mre.Set();
}
Related
I want to add elapsed time (minutes) to an GUI and do something else in parallel.
Everything I try does not succeed, it sticks in my gui. I add example:
namespace Backgrondworker
{
public partial class Form1 : Form
{
int aa = 0;
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
progressBar1.Value = 0;
progressBar1.Maximum = 10;
backgroundWorker1.RunWorkerAsync();
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
for(int i =1;i<=10;i++)
{
Thread.Sleep(1000);
backgroundWorker1.ReportProgress(0);
}
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
progressBar1.Value += 1;
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
MessageBox.Show("completed");
}
}
}
You should do the following
Create a Timer
Start the timer when you start the progress bar
In the timer, tick use the timespan class and Elapsed property to get the elapsed minutes and show them in a label.
Stop the Timer when the progressbar is at maxsize.
You put 0 in ReportProgress:
backgroundWorker1.ReportProgress(0);
Change this to:
int percent = (int)Math.Round((i * 100.0) / 10);
backgroundWorker1.ReportProgress(percent);
Dividing by 10 gives you the fraction of work done (you count 10 times in the loop) and multiplying by 100 is for getting the percent.
I explain:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Task.Run(() =>
{
for (int i = 1; i <= 10; i++)
{
Thread.Sleep(1000);
label2.Text = i.ToString();
}
});
Task.Run(() =>
{
for (int i = 1; i <= 10; i++)
{
Thread.Sleep(1000);
label3.Text = i.ToString();
}
});
}
}
got : System.InvalidOperationException: 'Cross-thread operation not valid: Control 'label3' accessed from a thread other than the thread it was created on.'
hi guys i tried to copy some files with this Code everything is good and the app will copy files but in copy progress i cant move my app or do anything
i tried to use thread but its not works i also use backgroundWorker but still nothing the only control that doesnt get stuck is progressBar its works fine here is my code :
public Form1()
{
InitializeComponent();
backgroundWorker1.Dispose();
backgroundWorker1.DoWork += BackgroundWorker_DoWork;
backgroundWorker1.RunWorkerCompleted += BackgroundWorker_RunWorkerCompleted;
backgroundWorker1.ProgressChanged += BackgroundWorker_ProgressChanged;
backgroundWorker1.WorkerReportsProgress = true;
backgroundWorker2.DoWork += BackgroundWorker2_DoWork;
backgroundWorker2.WorkerReportsProgress = true;
}
private void BackgroundWorker2_DoWork(object sender, DoWorkEventArgs e)
{
File.Copy(sourcePath, targetPath);
}
private void BackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
for (int i = 0; i < fileSize; i++)
{
int p = (i + 1) * 100 / Convert.ToInt32(fileSize);
backgroundWorker1.ReportProgress(p);
}
}
private void BackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
}
private void BackgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
lbProgress.Text = e.ProgressPercentage.ToString();
progressBar1.Value = e.ProgressPercentage;
}
private void btnTarget_Click(object sender, EventArgs e)
{
folderBrowser = new FolderBrowserDialog();
if (folderBrowser.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
targetPath += folderBrowser.SelectedPath + #"\" + fileName;
lbTarget.Text = targetPath;
}
}
private void btnSource_Click(object sender, EventArgs e)
{
op = new OpenFileDialog();
if (op.ShowDialog() == DialogResult.OK)
{
sourcePath += op.FileName;
lbSource.Text = sourcePath;
fileInfo = new FileInfo(sourcePath);
fileSize = fileInfo.Length / 1024;
fileName = fileInfo.Name;
MessageBox.Show(string.Format("File size is: {0} KB", fileSize));
}
}
private void btnCopy_Click(object sender, EventArgs e)
{
backgroundWorker1.RunWorkerAsync();
backgroundWorker2.RunWorkerAsync();
}
You're updating the progress bar faster than the UI can update, for every single byte of the file being copied in a tight loop. You're flooding the UI thread with pointless work.
Remove backgroundWorker1, it's not doing anything useful anyway. If you don't have a way to track the progress (which you don't with File.Copy), just use a progress bar without progress (set Style to Marquee).
For testing I created a simple winform application with a button, a label and a background worker and added the following corresponding events:
private void OnBackgroundWorkerDoWork(object sender, DoWorkEventArgs e)
{
var worker = (BackgroundWorker)sender;
for (int i = 0; i < 10; i++)
{
Thread.Sleep(500);
worker.ReportProgress(i * 10);
}
}
private void OnBackgroundWorkerProgressChanged(object sender, ProgressChangedEventArgs e)
{
labelProgress.Text = e.ProgressPercentage.ToString();
}
private void OnBackgroundWorkerRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
labelProgress.Text = "Done";
}
private void OnButtonProgressClick(object sender, System.EventArgs e)
{
backgroundWorker.RunWorkerAsync();
}
Works as expected.
Could You try to update Your DoWork to this:
private void BackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
int mainProgress = 0;
for (int i = 0; i < fileSize; i++)
{
int calculatedProgress = (i + 1) * 100 / Convert.ToInt32(fileSize);
if(calculatedProgress > mainProgress)
{
mainProgress = calculatedProgress;
backgroundWorker1.ReportProgress(mainProgress);
}
}
}
maybe You are doing so many updates that simply Window Thread is all the time updating only progress and don't have a time to make anything else?
My code that works:
private void textBox1_TextChanged(object sender, EventArgs e)
{
progressBar1.Visible = true;
}
private void textBox2_TextChanged(object sender, EventArgs e)
{
progressBar1.Visible = false;
}
If I add something for the computer to do, as seen in the following code example, the computer does not show the progress bar until it's done doing the computation. What I want it to do is show the progress bar first, then do the computation, then on some other event I want to hide the progress bar. Why can't I do it this way?
private void textBox1_TextChanged(object sender, EventArgs e)
{
progressBar1.Visible = true;
FindPrimeNumber(50000);
}
private void textBox2_TextChanged(object sender, EventArgs e)
{
progressBar1.Visible = false;
}
The requested FindPrimeNumber code:
public int FindPrimeNumber(int n)
{
int count = 0;
int a = 2;
while (count < n)
{
int b = 2;
int prime = 1;// to check if found a prime
while (b * b <= a)
{
if (a % b == 0)
{
prime = 0;
break;
}
b++;
}
if (prime > 0)
count++;
a++;
}
return (--a);
}
the FindPrimeNumber code is just something to make the computer do a task for a while, so I can test to see if my progress bar is going to show.
I figured it out. In this example, a user enters a 5 digit number in a text box, then a progress bar shows up on the form as it is processing the number in a math function, then the result is put into a second text box and the progress bar goes away.
private void textBox1_TextChanged(object sender, EventArgs e)
{
if (textBox1.TextLength == 5)
{
progressBar1.Visible = true;
int textFromTextBox1 = Int32.Parse(textBox1.Text);
backgroundWorker1.RunWorkerAsync(textFromTextBox1);
}
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
e.Result = FindPrimeNumber((int)e.Argument);
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
textBox2.Text = e.Result.ToString();
backgroundWorker1.CancelAsync();
}
private void textBox2_TextChanged(object sender, EventArgs e)
{
progressBar1.Visible = false;
}
Note: This example does not handle all exceptions, but it works great. As you can probably see in the code I am passing a value into the BackgroundWorker which gets passed into the FindPrimeNumber method, then I am retrieving the result out of the BackgroundWorker.
More notes for newbies:
I have the BackgroundWorker property WorkerSupportsCancellation set to True.
In WinForms, after dropping the BackgroundWorker onto the form, when you double click it, it will generate the DoWorkEventHandler for you, then in the Solution Explorer go to the Events and double click on RunWorkerCompleted so it can generated that for you as well. Otherwise, you will have to do a lot of manual code entry.
I am new in C#. I found some code which work on progressbar. What is does, when someone click on button start btnStartAsyncOperation_Click the progress bar starts increasing and when btnCancel_Click is pressed it cancel the operation. Here is the code
namespace BackgroundWorkerSample
{
public partial class Form1 : Form
{
BackgroundWorker m_oWorker;
public Form1()
{
InitializeComponent();
m_oWorker = new BackgroundWorker();
m_oWorker.DoWork += new DoWorkEventHandler(m_oWorker_DoWork);
m_oWorker.ProgressChanged += new ProgressChangedEventHandler(m_oWorker_ProgressChanged);
m_oWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(abcd);
m_oWorker.WorkerReportsProgress = true;
m_oWorker.WorkerSupportsCancellation = true;
}
void abcd(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Cancelled)
{
lblStatus.Text = "Task Cancelled.";
}
else if (e.Error != null)
{
lblStatus.Text = "Error while performing background operation.";
}
else
{
lblStatus.Text = "Task Completed...";
}
btnStartAsyncOperation.Enabled = true;
btnCancel.Enabled = false;
}
void m_oWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
progressBar1.Value = e.ProgressPercentage;
lblStatus.Text = "Processing......" + progressBar1.Value.ToString() + "%";
}
void m_oWorker_DoWork(object sender, DoWorkEventArgs e)
{
for (int i = 0; i < 100; i++)
{
Thread.Sleep(100);
m_oWorker.ReportProgress(i);
if (m_oWorker.CancellationPending)
{
e.Cancel = true;
m_oWorker.ReportProgress(0);
return;
}
}
//Report 100% completion on operation completed
m_oWorker.ReportProgress(100);
}
private void btnStartAsyncOperation_Click(object sender, EventArgs e)
{
btnStartAsyncOperation.Enabled = false;
btnCancel.Enabled = true;
//Start the async operation here
m_oWorker.RunWorkerAsync();
}
private void btnCancel_Click(object sender, EventArgs e)
{
if (m_oWorker.IsBusy)
{
//Stop/Cancel the async operation here
m_oWorker.CancelAsync();
}
}
private void progressBar1_Click(object sender, EventArgs e)
{
}
private void lblStatus_Click(object sender, EventArgs e)
{
}
private void button1_Click(object sender, EventArgs e)
{
}
private void button2_Click(object sender, EventArgs e)
{
}
}
}
Now I added 2 more button, button1 to pause and button2 to resume. Since I could not find any method to resume, I had to use CancelAsync() function when I press pause and I keep the value of progress bar in a global variable. Then when I press resume I start the progress bar again using RunWorkerAsync. But the problem is, I can not send the value of global variable in this function so it start from 0 progress.
I tried to use thread.sleep(infinite time here) when someone press pause and then stop the thread when someone press resume. Still the problem is, I can not press any button in this situation. Still if I enable button they don't work.
Please give me some solution.
You could try having your own variable, i.e
bool isPaused = false;
When someone clicks your pause button...
isPaused = true;
And set it to false when someone clicks resume. Finally, in your for loop in your doWork method, make it wait until that variable is false.
while (isPaused)
{
Thread.Sleep(100);
}
Let me know how this works out for you.
What I want is when some method is doing some task UI keeps itself active and I want to show the progress of the work in a progress-bar.
I have a method, a BackGroundWorker and a Progressbar. I want to call the method when BackGroundWorker starts running and show the progress. The method contains a loop. So, it can report the progress.
So, what can be done?
private void Form1_Load(object sender, EventArgs e)
{
// TODO: This line of code loads data into the 'dataSet1.TBLMARKET' table. You can move, or remove it, as needed.
myBGWorker.WorkerReportsProgress = true;
}
private void myBGWorker_DoWork(object sender, DoWorkEventArgs e)
{
parseFiles();
}
private void myBGWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
myProgressBar.Value = e.ProgressPercentage;
}
private void myBGWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
MessageBox.Show("Done");
}
private void parseButton_Click(object sender, EventArgs e)
{
myBGWorker.RunWorkerAsync();
}
public void parseFiles()
{
for()
{
//parsing
myBGWorker.ReportProgress(...);
}
}
But it's not working. The Progressbar is not updating. Only a small progress is showing after the MessageBox "Done".
Instead of using one ParseFiles method (which should depend on myBGWorker) use loop and method which parse one file. Report progress percentage in that loop:
private void parseButton_Click(object sender, EventArgs e)
{
parseButton.Enabled = false;
myBGWorker.RunWorkerAsync();
}
private void myBGWorker_DoWork(object sender, DoWorkEventArgs e)
{
for(int i = 0; i < filesCount; i++)
{
ParseSingleFile(); // pass filename here
int percentage = (i + 1) * 100 / filesCount;
myBGWorker.ReportProgress(percentage);
}
}
void myBGWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
myProgressBar.Value = e.ProgressPercentage;
}
void myBGWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
parseButton.Enabled = true;
MessageBox.Show("Done");
}
To. soham.m17
using with sender argument
private void myBGWorker_DoWork(object sender, DoWorkEventArgs e)
{
var worker = sender as BackgroundWorker;
for(int i = 0; i < filesCount; i++)
{
ParseSingleFile(); // pass filename here
int percentage = (i + 1) * 100 / filesCount;
worker.ReportProgress(percentage); // use not myBGWorker but worker from sender
}
}
I am sorry about the question. Actually the code works fine. It was not showing the Progressbar as the argument in myBGWorker.ReportProgress() was fraction and not percentage. So, it was not showing it. Sorry for the inconvenience.
Moderator may delete this thread. Otherwise it can be a tutorial for others.