I don't have a thorough knowledge about controlling threads in c#. I want to create a progress bar while running a method.
I have two forms:
Form1 is the form which show up as you run the app. It has a button called btnScrape. When it is clicked the method should be called, the form with the progress bar should show up. Form1 should be disabled to the user until the progress bar is completed.
ProgressBarForm - this has the progress bar and a label.
The code is as follows.
//In Form1.cs I have a button.
private void btnScrape_Click(object sender, EventArgs e)
{
//gather data for folloeing parameters from the form.
Controller cntrlr = new Controller(urlFilePath, destinationPath, destinationfilename,cmbDepth.SelectedIndex);
cntrlr.Vmain(); // this is the method in controller class. while this is running i want show the progress bar.
}
// in Contrller class
class Controller{
List<string> urlList = null;
URLFileReader urlFileReader = null;
HTTPWorker httpWorker = null;
SourceReader srcreader = null;
ReportWriter reportWriter = null;
string urlFilePath, destinationPath, destinationFileName;
int depth;
public Controller(string urlFilePath,string destinationPath,string destinationFileName,int depth)
{
this.urlFilePath = urlFilePath;
this.destinationPath = destinationPath;
this.destinationFileName = destinationFileName;
this.urlList = new List<string>();
this.urlFileReader = new URLFileReader();
this.httpWorker = new HTTPWorker(this.destinationPath);
this.reportWriter = new ReportWriter(this.destinationPath,this.destinationFileName);
this.srcreader = new SourceReader(this.reportWriter);
this.depth = depth;
}
//this is the method
public void Vmain(){
this.urlFileReader.ReadURL(urlFilePath);
this.urlList = urlFileReader.geturlList();
string pageSrc;
foreach (string requestUrl in urlList)
{
//do sruff for requestUrl
//the progressbar should move as the urlList iterate.
//additionally i want the label on the top of progress bar to display the current "requestUrl"
//as the urlList is over i want quit from the progressbar window and come back to Form1. Till the progrss bar is completed Form1 should be disabled for the user.
}
}
}
Please explain what is happening there and give a working code if you can. Thank you in advance. There were not any perfect answer that worked for me, even though I spent two days for this. I tried with BackgroundWorkerand threads. But no solution found. :(
In the main form you could use this code:
private Progressfrm _loadForm;
private void ShowProgress()
{
ToggleForm();
_loadForm = new Progressfrm();
_loadForm.ShowDialog();
var tcheck = new Thread(CheckLoadedProgress);
tcheck.Start();
//do stuff here
}
private void CheckLoadedProgress()
{
while (_loadForm.IsAccessible) { }
ToggleForm();
}
private void ToggleForm()
{
Invoke(new Action(() => Enabled = !Enabled));
}
private void btnScrape_Click(object sender, EventArgs e)
{
var tform = new Thread(ShowProgress);
tform.Start();
}
Then the Progress-Form will appear until it is filled:
private ProgressBar _progressBar;
private void Progressfrm_Shown(object sender, EventArgs e)
{
_progressBar = new ProgressBar { Size = new Size(100, 20), Location = new Point(10, 10) };
Controls.Add(_progressBar);
_progressBar.Show();
Refresh();
LoadProgress();
}
private void LoadProgress()
{
while (_progressBar.Value < 100)
{
_progressBar.Value++;
Thread.Sleep(100);
}
Close();
}
On this Form you have to add the Event Shown and add the code like in my example. Hope this helps.
Use BackgroundWorker class to output progressBar and statusLabel changes:
BackgroundWorker bgw;
private void btnScrape_Click(object sender, EventArgs e)
{
bgw = new BackgroundWorker();
bgw.WorkerReportsProgress = true;
bgw.DoWork += new DoWorkEventHandler(bgw_DoWork);
bgw.ProgressChanged += new ProgressChangedEventHandler(bgw_ProgressChanged);
bgw.RunWorkerAsync();
}
void bgw_DoWork(object sender, DoWorkEventArgs e)
{
for (int i = 1; i <= 100; i++)
{
Thread.Sleep(100);
bgw.ReportProgress(i);
}
}
private void bgw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
progressBar1.Value = e.ProgressPercentage;
}
This is only an example how to update controls in an asynchron way.
Related
I want to show 4 videos at the same time in Windows Forms using Task. I have 4 video play clicks. When I click the first video play button, first video plays, when I click the second video play button, second video plays and first video continue to play at same time. But, when I click third video play button; first video stops and second video and third video plays at the same time. In the same way, when I click the fourth video play button, the second video stops, just third and fourth video plays at the same time.
My code:
private async void play1_Click(object sender, EventArgs e)
{
string inputPath = textBox1.Text;
await Task.Run(() => {
ReadFrames1(inputPath); });
}
and
public void ReadFrames1(string inputPath)
{
using (var vFReader = new VideoFileReader())
{
vFReader.Open(inputPath);
for (int i = 0; i < vFReader.FrameCount; i++)
{
Bitmap videoFrame = vFReader.ReadVideoFrame();
System.Drawing.Image pic = resizeImage(new Bitmap(videoFrame), new Size(305, 267));
pictureBox1.Image = new Bitmap(pic);
}
vFReader.Dispose();
vFReader.Close();
}
}
play2_Click(), play3_Click(), play4_Click() methods are same with play1_Click(). (I mean for example play2_Click() method calls ReadFrames2() and shows on PictureBox2.) Where I am wrong?
For multithreading via WinForms use BackgroundWorker.
here is a code example which works for me. hope it will help you:
public Form1()
{
InitializeComponent();
}
private BackgroundWorker CreateBackgroundWorker()
{
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += ReadFrames;
worker.RunWorkerCompleted += worker_RunWorkerCompleted;
return worker;
}
private void worker_RunWorkerCompleted(object sender,
RunWorkerCompletedEventArgs e)
{
Button playButton = (Button) e.Result;
playButton.Enabled = true;
}
private void ReadFrames(object sender, DoWorkEventArgs e)
{
BackgroundWorker backgroundWorker = (BackgroundWorker) sender;
(string path, PictureBox pictureBox, Button playButton) arguments = ((string, PictureBox, Button)) e.Argument;
using(var vFReader = new VideoFileReader())
{
vFReader.Open(arguments.path);
for (int i = 0; i < vFReader.FrameCount; i++)
{
arguments.pictureBox.Image = new Bitmap(vFReader.ReadVideoFrame(), arguments.pictureBox.Size);
}
vFReader.Dispose();
vFReader.Close();
}
e.Result = arguments.playButton;
}
private void play1_Click(object sender, EventArgs e)
{
var worker = CreateBackgroundWorker();
worker.RunWorkerAsync((textBox1.Text, pictureBox1, play1));
play1.Enabled = false;
}
private void play2_Click(object sender, EventArgs e)
{
var worker = CreateBackgroundWorker();
worker.RunWorkerAsync((textBox2.Text, pictureBox2, play2));
play2.Enabled = false;
}
private void play3_Click(object sender, EventArgs e)
{
var worker = CreateBackgroundWorker();
worker.RunWorkerAsync((textBox3.Text, pictureBox3, play3));
play3.Enabled = false;
}
private void play4_Click(object sender, EventArgs e)
{
var worker = CreateBackgroundWorker();
worker.RunWorkerAsync((textBox4.Text, pictureBox4, play4));
play4.Enabled = false;
}
I am making a search utility and using a BackgroundWorker to search. I want that as soon as the first result is found , a new window should open up with a ListBox with the first element displayed. Now, I want that as soon as subsequent results are found, the ListBox should be updated with those results.
The method thought by me was to report the progress as soon as results are found and pass "New" and "Update" as userState to the method.
Based on the userState, I can decide whether to create a new Form or update and existing one.
Here is the code :-
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
if (e.UserState.ToString() == "New")
{
Form ResultForm = new Form();
ResultForm.Name = "ResultForm" + i.ToString();
LastFormName = ResultForm.Name;
ListBox ResultListBox = new ListBox();
ResultListBox.DataSource = SearchList;
ResultListBox.Name = "ResultListBox" + i.ToString();
LastListName = ResultListBox.Name ;
ResultForm.Container.Add(ResultListBox);
ResultListBox.Show();
ResultForm.Show();
i++;
}
else
{
;
}
}
I have stored the names of the Last open Form and it's ListBox in the variables LastFormName and 'LastListName'.
I am unable to understand what to put in the else condition, so as to update the ListBox.
What I would do is expose some properties on the popup form so that you can tell if it is open and have access to the list box.
public partial class Popup : Form
{
public bool isOpen;
public ListBox PopupListBox;
public Popup()
{
InitializeComponent();
}
void Popup_FormClosing(object sender, FormClosingEventArgs e)
{
isOpen = false;
}
private void Popup_Load(object sender, EventArgs e)
{
this.FormClosing += Popup_FormClosing;
PopupListBox = popupListBox;
}
}
Then on the calling form I would subscribe to the ProcessedChanged Event and update the listbox with the data you are passing through the ProcessedChangedEventArgs. Here is the code for the calling form
public partial class Form1 : Form
{
Popup popupForm = new Popup();
BackgroundWorker backgroundWorker = new BackgroundWorker();
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
backgroundWorker.WorkerSupportsCancellation = true;
backgroundWorker.WorkerReportsProgress = true;
backgroundWorker.DoWork += backgroundWorkerDoWork;
backgroundWorker.ProgressChanged += backgroundWorkerProgressChanged;
backgroundWorker.RunWorkerCompleted += backgroundWorkerRunWorkerCompleted;
}
void backgroundWorkerRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if ((e.Cancelled == true))
{
//What do you want to do if Cancelled?
}
else if (!(e.Error == null))
{
//What do you want to do if there is an error?
}
else
{
//What do you want to do when it is done?
}
}
void backgroundWorkerProgressChanged(object sender, ProgressChangedEventArgs e)
{
if (!popupForm.isOpen || popupForm == null)
{
popupForm = new Popup();
popupForm.Show();
popupForm.isOpen = true;
}
else
{
popupForm.Activate();
popupForm.WindowState = FormWindowState.Normal;
}
popupForm.PopupListBox.Items.Add(e.ProgressPercentage.ToString() + "%");
}
void backgroundWorkerDoWork(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));
}
}
}
private void buttonStart_Click(object sender, EventArgs e)
{
if (backgroundWorker.IsBusy != true)
{
backgroundWorker.RunWorkerAsync();
}
}
private void buttonCancel_Click(object sender, EventArgs e)
{
if (backgroundWorker.WorkerSupportsCancellation == true)
{
backgroundWorker.CancelAsync();
}
}
}
You shouldn't be doing work in the ProgressChanged event handler
You won't have access to the results as it is only passed an int for progress and user state
This is on the UI thread. The entire point is to do your processing on a background thread
The name DoWork event handler is clear that this is where you should do your processing.
In answer to your question. Since you create the ListBox in your event handler it goes out of scope outside the if statement. You need to create this in a more global scope. Then to add to it ResultListBox.Items.Add("ResultListBox" + i.ToString());
my main problem is when i add dynamically a progressbar on flowLayoutPanel1 for each request then how can i increase right progressbar value frombackgroundWorker1_ProgressChanged event
when user click on start button then i will call RunWorkerAsync function of background worker....it is fine. here i am writing a sample code and try to show my problem.
my form has one textbox, one button and one flowLayoutPanel1 with FlowDirection topdown.
when user enter any url in textbox and click on start button then i will start file download with BackGroundWorker and add one progress bar dynamically on flowLayoutPanel1. 10 file can be downloaded at a time. so when user enter ten url one after after one and click on submit button then ten file will be downloading in background.
my problem is how to increment 10 progress bar progress properly from backgroundWorker1_ProgressChanged event another issue is when any file download will complete then the progress bar for which it has been created will be removed from panel
here is my full code. please have a look and tell me what i need to do to achieve my task. if anyone see there is problem in my code for which a dead lock may appear then also please guide me how to avoid dead lock. here is my code
public partial class Form1 : Form
{
static int pbCounter = 1;
public Form1()
{
InitializeComponent();
}
private void btnStart_Click(object sender, EventArgs e)
{
ProgressBar pb = new ProgressBar();
if (pbCounter <= 10)
{
pb.Width = txtUrl.Width;
flowLayoutPanel1.Controls.Add(pb);
pbCounter++;
System.ComponentModel.BackgroundWorker backgroundWorker1 = new System.ComponentModel.BackgroundWorker();
backgroundWorker1.DoWork += new DoWorkEventHandler(backgroundWorker1_DoWork);
backgroundWorker1.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorker1_RunWorkerCompleted);
backgroundWorker1.ProgressChanged += new ProgressChangedEventHandler(backgroundWorker1_ProgressChanged);
backgroundWorker1.RunWorkerAsync();
}
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
// Get the BackgroundWorker that raised this event.
System.ComponentModel.BackgroundWorker worker = sender as System.ComponentModel.BackgroundWorker;
// Assign the result of the computation
// to the Result property of the DoWorkEventArgs
// object. This is will be available to the
// RunWorkerCompleted eventhandler.
//#e.Result = ComputeFibonacci((int)e.Argument, worker, e);
}
// This event handler deals with the results of the
// background operation.
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
// First, handle the case where an exception was thrown.
if (e.Error != null)
{
MessageBox.Show(e.Error.Message);
}
else if (e.Cancelled)
{
//# "Canceled";
}
else
{
pbCounter--;
// Finally, handle the case where the operation
// succeeded.
//#resultLabel.Text = e.Result.ToString();
}
}
// This event handler updates the progress bar.
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
this.progressBar1.Value = e.ProgressPercentage;
}
}
MY UPDATED PART
public partial class Form1 : Form
{
static int pbCounter = 1;
public Form1()
{
InitializeComponent();
}
private void btnStart_Click(object sender, EventArgs e)
{
ProgressBar pb = new ProgressBar();
if (pbCounter <= 10)
{
//pb.Step = 10;
pb.Minimum = 0;
//pb.Maximum = 100;
pb.Width = txtUrl.Width;
flowLayoutPanel1.Controls.Add(pb);
pbCounter++;
MyBackgroundWorker backgroundWorker1 = new MyBackgroundWorker();
backgroundWorker1.pbProgress = pb;
backgroundWorker1.WorkerReportsProgress = true;
backgroundWorker1.DoWork += new DoWorkEventHandler(backgroundWorker1_DoWork);
backgroundWorker1.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorker1_RunWorkerCompleted);
backgroundWorker1.ProgressChanged += new ProgressChangedEventHandler(backgroundWorker1_ProgressChanged);
backgroundWorker1.RunWorkerAsync(txtUrl.Text);
}
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
int input = int.Parse(e.Argument.ToString());
for (int i = 1; i <= input; i++)
{
Thread.Sleep(2000);
(sender as MyBackgroundWorker).ReportProgress(i * 10);
if ((sender as MyBackgroundWorker).CancellationPending)
{
e.Cancel = true;
return;
}
}
}
// This event handler deals with the results of the
// background operation.
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
// First, handle the case where an exception was thrown.
if (e.Error != null)
{
MessageBox.Show(e.Error.Message);
}
else if (e.Cancelled)
{
//# "Canceled";
}
else
{
ProgressBar pb = (sender as MyBackgroundWorker).pbProgress;
if (pb != null)
{
//pb.Value = 100;
//pb.Update();
while (pb.Value <= pb.Maximum)
{
//Thread.Sleep(1000);
flowLayoutPanel1.Controls.Remove(pb);
break;
}
}
// Finally, handle the case where the operation
// succeeded.
}
}
// This event handler updates the progress bar.
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
ProgressBar pb = (sender as MyBackgroundWorker).pbProgress;
pb.Refresh();
//if (e.ProgressPercentage < pb.Maximum)
// pb.Value = e.ProgressPercentage + 10;
pb.Value = e.ProgressPercentage ;
Application.DoEvents();
}
}
public class MyBackgroundWorker : System.ComponentModel.BackgroundWorker
{
public ProgressBar pbProgress = null;
public MyBackgroundWorker()
{
}
public MyBackgroundWorker(string name)
{
Name = name;
}
public string Name { get; set; }
}
This is one way of doing it -
Create your own class inherited from BackgroundWorker, Add a public variable of type ProgressBar.
Each time you add a BackgroundWorker and Progressbar dynamically, pass the progressbar object to your class.
Your derived Class -
public class MyBackgroundWorker : BackgroundWorker
{
public ProgressBar pbProgress = null;
public void BackgroundWorker()
{
}
}
Button Event Code -
private void btnStart_Click(object sender, EventArgs e)
{
ProgressBar pb = new ProgressBar();
if (pbCounter <= 10)
{
pb.Width = txtUrl.Width;
flowLayoutPanel1.Controls.Add(pb);
pbCounter++;
MyBackgroundWorker backgroundWorker1 = new MyBackgroundWorker();
backgroundWorker1.pbProgress = pb;
backgroundWorker1.DoWork += new DoWorkEventHandler(backgroundWorker1_DoWork);
backgroundWorker1.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorker1_RunWorkerCompleted);
backgroundWorker1.ProgressChanged += new ProgressChangedEventHandler(backgroundWorker1_ProgressChanged);
backgroundWorker1.RunWorkerAsync();
}
}
Progress Changed Event -
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
(sender as MyBackgroundWorker).pbProgress.Value = e.ProgressPercentage;
}
First declare a global dictionary and a GetInstance Method to access the form instance
public partial class Form1 : Form
{
Dictionary<String, ProgressBar> progressBars = new Dictionary<String, ProgressBar>();
static Form1 _form1 = null;
static int pbCounter = 1;
public Form1()
{
InitializeComponent();
_form1 = this;
}
public static Form1 GetInstance() {
return _form1;
}
Then with each url you get and you must be creating pb for each of them, just add them in this dictionary too
progressBars.Add("file1", pb1);
progressBars.Add("file2", pb2);
progressBars.Add("file3", pb3);
progressBars.Add("file4", pb4);
Create a function in form.cs in which you can pass the progressbar and then you can manually set the value of it.
public void ProgessReport(ProgressBar pb, int value)
{
if (pb.InvokeRequired)
{
pb.Invoke(new MethodInvoker(delegate { ProgessReport(pb, value); }));
} else
{
pb.Value = value;
}
}
now from where you are downloading the file you just have to call
Form1.GetInstance().ProgessReport(Form1.GetInstance().progressBars["file1"], 10);
Form1.GetInstance().ProgessReport(Form1.GetInstance().progressBars["file1"], 20);
Form1.GetInstance().ProgessReport(Form1.GetInstance().progressBars["file1"], 100);
and when your second file downloads then
Form1.GetInstance().ProgessReport(Form1.GetInstance().progressBars["file2"], 10);
Form1.GetInstance().ProgessReport(Form1.GetInstance().progressBars["file2"], 20);
Form1.GetInstance().ProgessReport(Form1.GetInstance().progressBars["file2"], 100);
like this ..
I have a situation here. I have a picture box in windows form and i let user to browse a picture by using openfileupload control and after that i set selected picture into picture box. Here is my code:
namespace Employee_Card_Manager
{
public partial class Form1 : Form
{
string Chosen_File = "";
public Form1()
{
InitializeComponent();
}
private void label1_Click(object sender, EventArgs e)
{
}
private void openFileDialog1_FileOk(object sender, CancelEventArgs e)
{
}
private void button1_Click(object sender, EventArgs e)
{
selectpic.Title = "Browse Employee Picture!";
selectpic.InitialDirectory = System.Environment.GetFolderPath(Environment.SpecialFolder.Personal);
selectpic.FileName = "";
selectpic.Filter = "JPEG Images|*.jpg|GIF Images|*.gif|BITMAPS|*.bmp";
if (selectpic.ShowDialog() != DialogResult.Cancel)
{
progressBar1.Enabled = true;
Chosen_File = selectpic.FileName;
pictureBox1.Image = Image.FromFile(Chosen_File);
progressBar1.Enabled = false;
}
}
}
}
It is working perfectly! I need to add some modification to this code so that when user browse a picture and presses Open button my application will show him a progress bar that this picture is being uploaded in mean time...
I have found the following code to show a progress bar:
namespace ProgressBarSampleCSharp
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void CreateButton_Click(object sender, EventArgs e)
{
ProgressBar pBar = new ProgressBar();
pBar.Location = new System.Drawing.Point(20, 20);
pBar.Name = "progressBar1";
pBar.Width = 200;
pBar.Height = 30;
//pBar.Dock = DockStyle.Bottom;
pBar.Minimum = 0;
pBar.Maximum = 100;
pBar.Value = 70;
Controls.Add(pBar);
}
}
}
But i have no idea how to fit this code into my class so that it will show progress bar in the mean time when picture is being uploaded!
any ideas??
I have an old code adapted to answer your question.
I let the ProgressBar control out of the InitializeComponent just for clarity.
However, I think that when you run this code, you'll remove the progress bar completely.
namespace Employee_Card_Manager
{
public partial class Form1 : Form
{
ProgressBar pBar = new ProgressBar();
string Chosen_File = "";
public Form1()
{
InitializeComponent();
CreateProgressBar();
}
private void CreateProgressBar()
{
pBar.Location = new System.Drawing.Point(20, 20);
pBar.Name = "progressBar1";
pBar.Width = 200;
pBar.Height = 30;
pBar.BackColor = Color.Transparent;
pBar.Minimum = 0;
pBar.Maximum = 100;
pBar.Value = 0;
Controls.Add(pBar);
}
private void button1_Click(object sender, EventArgs e)
{
selectpic.Title = "Browse Employee Picture!";
selectpic.InitialDirectory = System.Environment.GetFolderPath(Environment.SpecialFolder.Personal);
selectpic.FileName = "";
selectpic.Filter = "JPEG Images|*.jpg|GIF Images|*.gif|BITMAPS|*.bmp";
if (selectpic.ShowDialog() != DialogResult.Cancel)
{
Chosen_File = selectpic.FileName;
pictureBox1.LoadCompleted += new AsyncCompletedEventHandler(pictureBox1_LoadCompleted);
pictureBox1.LoadProgressChanged += new ProgressChangedEventHandler(pictureBox1_LoadProgressChanged);
pictureBox1.WaitOnLoad = false;
pictureBox1.LoadAsynch(Chosen_file);
}
}
private void pictureBox1_LoadCompleted(object sender, AsyncCompletedEventArgs e)
{
pBar.Value = 0;
}
private void pictureBox1_LoadProgressChanged(object sender, ProgressChangedEventArgs e)
{
pBar.Value = e.ProgressPercentage;
}
}
}
If it truly is taking a long time to 'upload' you could use the FileSystemWatcher's changed event. Every time it is fired you increment the progressbar some fraction of the total known file size.
OK so I've have a problem looking like this.
public Class A{
public A(){
progressBar.Style = ProgressBarStyle.Marquee;
progressBar.MarqueeAnimationSpeed = 0;
}
public void DoSomething(){
if(checkpasses){
progressBar.MarqueeAnimationSpeed = 100;
//Do something here...
progressBar.MarqueeAnimationSpeed = 0;
}
else
//Do nothing...
}
}
The problem is that my progressbar wont start moving at all. First I figured that it wont create a new thread by itself (which I find wired) so I tried creating a thread but still the same result. Nothing happens. Is it something I've forgotten?
Call
Application.EnableVisualStyles();
at the very beginning of your application.
Your "do something here" code is going to block the UI thread so you will not see the progress bar update until after the DoSomething method completes. At that time you are setting the animation speed back to 0.
Try putting your "do something here" code on a separate thread. When that thread completes set the animation speed back to 0.
Something like this:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
backgroundWorker1.DoWork += new DoWorkEventHandler(backgroundWorker1_DoWork);
backgroundWorker1.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorker1_RunWorkerCompleted);
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
progressBar1.MarqueeAnimationSpeed = 0;
progressBar1.Style = ProgressBarStyle.Blocks;
progressBar1.Value = progressBar1.Minimum;
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
DoSomething();
}
private void button1_Click(object sender, EventArgs e)
{
progressBar1.Style = ProgressBarStyle.Marquee;
progressBar1.MarqueeAnimationSpeed = 100;
backgroundWorker1.RunWorkerAsync();
}
private void DoSomething()
{
Thread.Sleep(2000);
}
}
I am not sure if this is the best solution, but I have it this way:
//this is the action item (button click)
private void importSFNFReportButton_Click(object sender, EventArgs e)
{ //I run
backgroundWorker6Progress.RunWorkerAsync(); //this is how I start the progress bar 'movement'
bgwImportSF.RunWorkerAsync(); //this is another task that is lauchned after the progress bar is initiated
}
This is actual background worker
private void backgroundWorker6Progress_DoWork(object sender, DoWorkEventArgs e)
{
bool cont = true;
while (cont)
{
PauseForMilliSeconds(100);
updateProgressbar1(false);
if (noTasksExistCheck())
{
updateProgressbar1(true);
cont = false;
}
}
}
this is a delegate- I call it to auto-increase the progress bar indicator
delegate void updateProgressBarStatus(bool done);
private void updateProgressbar1(bool done)
{
if (progressBar1.InvokeRequired)
{
updateProgressBarStatus del = new updateProgressBarStatus(updateProgressbar1);
progressBar1.Invoke(del, new object[] { done });
}
else
{
if (progressBar1.Value == progressBar1.Maximum)
{
progressBar1.Value = progressBar1.Minimum;
}
progressBar1.PerformStep();
if (done == true)
{
progressBar1.Value = progressBar1.Minimum;
}
}
}
I control it via the function that has to check a global varibale
noTasksExistCheck()
This is the timer pause
public static DateTime PauseForMilliSeconds(int MilliSecondsToPauseFor)
{
System.DateTime ThisMoment = System.DateTime.Now;
System.TimeSpan duration = new System.TimeSpan(0, 0, 0, 0, MilliSecondsToPauseFor);
System.DateTime AfterWards = ThisMoment.Add(duration);
while (AfterWards >= ThisMoment)
{
System.Windows.Forms.Application.DoEvents();
ThisMoment = System.DateTime.Now;
}
return System.DateTime.Now;
}
Just to complement a bit more, the solution suggested by Dave will only work if Konstantin's suggested code exists. Otherwise, one should think of manually increasing the progressbar.value in a loop by the following code within the DoWork:
BeginInvoke(new MethodInvoker( () => progressBarSave.Value += progressBarSave.Step));