0

I'm making a loading tool for all of my current / future programs that I intend to create. I made a loader and an invisible button, that I want to turn visible at a certain stage, but I cannot figure out how to implement it with my current code which looks like this:

button1.Visible = false; int i; progressBar1.Minimum = 0; progressBar1.Maximum = 231; // set to this "random" number because its the pixel length of the bar for (i = 0; i <= 220; i++) { progressBar1.Value = i; } if(progressBar1.Value == 220) //Stops BEFORE the end of the bar, to make the invisible button appear and make it possible to "skip" it { button1.Visible = true; } 

When I run it my progressbar is already at the value 220, and I can somehow understand that as there aren't any "steps" to take. But I am not entirely sure if I can fix it by changing something in my current code or change the code to have steps in it.

8
  • Your problem is that your progress bar visually changes from 0 to the max value ? Commented Nov 18, 2015 at 17:40
  • Well, first, you're running this on the UI thread, which will cause problems (hanging) when you're actually doing work to display. Second, it seems to already be at 220 because, well, do you have any idea how fast your computer can count to 220? you can add a Thread.Sleep in there to have it go slower. Commented Nov 18, 2015 at 17:42
  • thread.sleep was what I was looking for! However now I just need to impliment it, and I assume that putting my thread to sleep during my " if(progressbar... == 220 " would make it sleep right away as well, then ? Commented Nov 18, 2015 at 17:42
  • Yes, but as DrewJordan says, add a sleep will not be enough. You need to move your treatment in an other thread than the "UI thread", otherwise your interface will be updated only at the end of the treatment. Commented Nov 18, 2015 at 17:45
  • I think I'll just add a timer that starts on form_load and activate the button on timer_tick - unless you guys have a better suggestion? Commented Nov 18, 2015 at 17:50

2 Answers 2

2

Without a good, minimal, complete code example that reliably reproduces the problem and shows your precise scenario, it is impossible to know for sure what the best answer would be. That said, if I understand correctly you have: a progress bar; and a button; and some process that, when it is nearly done, you want for the button to be shown, and of course for the progress to be updated continuously.

There are a number of good answers on Stack Overflow already discussing the correct use of background tasks, asynchronous methods, and progress bars, so I won't belabor those points too much. But I will show quickly how your code might be restructured to accomplish what you want.

Let's assume this all starts with the click of some button (maybe even the one you are setting to be invisible). Then we might refactor your code above, which presumably appears in the event handler for that button click, to look something like this:

private async void button1_Click(object sender, EventArgs e) { button1.Visible = false; progressBar1.Minimum = 0; progressBar1.Maximum = 231; // Set up a callback that can be used to report progress on the UI thread Progress<int> progress = new Progress<int>(i => { progressBar1.Value = i; if (progressBar1.Value == 220) { button1.Visible = true; } }); // Perform your task; this will run in a different thread from the current, // UI thread, allowing the UI thread to do useful things like hiding the button // and updating the progress bar. Use of "await" here is what allows this // method to return, _temporarily_, so that the UI thread can continue to work await Task.Run(() => { for (i = 0; i <= 220; i++) { // do NOT do this in real code...this is just here to represent _some_ kind // of time-consuming operation that justifies the use of the progress bar //in the first place Thread.Sleep(250); // Now report the progress value; the "progress" object will handle // marshaling back to the UI thread to call the anonymous method // declared above during the initialization of "progress" progress.Report(i); } }); // Do any post-processing cleanup, UI updating, etc. here. This code // will execute only after the task started above has completed. } 


EDIT:

Per the new requirements from the OP, here is a version of the above that makes the button visible only after all of the processing is done:

private async void button1_Click(object sender, EventArgs e) { button1.Visible = false; progressBar1.Minimum = 0; progressBar1.Maximum = 231; // Set up a callback that can be used to report progress on the UI thread Progress<int> progress = new Progress<int>(i => { progressBar1.Value = i; }); // Perform your task; this will run in a different thread from the current, // UI thread, allowing the UI thread to do useful things like hiding the button // and updating the progress bar. Use of "await" here is what allows this // method to return, _temporarily_, so that the UI thread can continue to work await Task.Run(() => { for (i = 0; i <= 220; i++) { // do NOT do this in real code...this is just here to represent _some_ kind // of time-consuming operation that justifies the use of the progress bar //in the first place Thread.Sleep(250); // Now report the progress value; the "progress" object will handle // marshaling back to the UI thread to call the anonymous method // declared above during the initialization of "progress" progress.Report(i); } }); // Do any post-processing cleanup, UI updating, etc. here. This code // will execute only after the task started above has completed. button1.Visible = true; } 
Sign up to request clarification or add additional context in comments.

2 Comments

I am unsure whether I should comment here or simply answer my own post, as I forgot to do it yesterday after I found a solution shortly after I Paul and Drew took their time to help - but regardless: thank you, Peter. What I did was first to set the button as invislbe under the form_load, then add a background worker to to report "_ProgressChanged", as well as report my progress under "_DoWork". for my progressBar Afterwards I made the button appear in the "_RunWorkerCompleted" section, as well as launch my desired form in a "yes, no cancel" dialog box. I dropped the 80% and just set it 100
@Storm: if you have answered your question yourself, by all means do post your solution as a good, accepted answer (be sure to include enough code example to make it clear) so that others can benefit from that. For what it's worth, the above is equivalent to your BackgroundWorker approach, but uses the modern TPL and async/await idioms. IMHO it's just as useful an approach as what you're using now. I will add a version of the code that shows the button at the end rather than during the task, so that it better matches your new criteria.
0

As poor as my question was, I was able to get a few people to actually understand it and help me get started with it. What I wanted was to have a button that would appear after my progressbar was done loading, but I hadn't figured out the optimal way to do so - I have now.

My full intentions were to create a Loader, which I have now succesfully done. However I have taken out the "unnecessary" parts to simply answer my own question. Should anyone be interested, I would gladly post it - I might even do it to get some constructive criticism, as I am as new and just doing this to satisfy my own curiosity.

 namespace RandomLoader { public partial class Form1 : Form { public Form1() { InitializeComponent(); bw.RunWorkerAsync(); } private void Form1_Load(object sender, EventArgs e) { bw.WorkerReportsProgress = true; //The button was already made non-visible in my form's property window } private void bw_ProgressChanged(object sender, ProgressChangedEventArgs e) { progressBar1.Value = e.ProgressPercentage; this.Text = e.ProgressPercentage.ToString() + " %"; // to make the form change name to the current progress of the Progress bar (I didnt want to make the text on top of the progress bar) } private void bw_DoWork(object sender, DoWorkEventArgs e) { for (int i = 1; i <= 100; i++) { Thread.Sleep(#); // to make the progress bar look realistic, so it had tiny stops and stuttering, like an actually functioning download bar does.wasnt instantly at 100% (I used 100 as in 1/10th of a second stutters before the bw would update the bar) bw.ReportProgress(i); // report progress from the background worker } } private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) // Once my bar is done loading I want it to sleep for just a tiny bit, because the background worker is done before the visualization on the progressbar is done. { Thread.Sleep(#); button1.Visible = true; this.Text = "Done Loading"; //Instead of making a convertion from string to int in my ProgressChanged event, I simply made it so that once it was done, it would say "done loading" rather than the current % } private void button1_Click(object sender, EventArgs e) // As this was a loader for my next few programs, I want it to open my not yet finished program, so an empty form will suffice as an example. { Form2 f2 = new Form2(); f2.Show(); } } 

I believe this is what there is relevant to my question, however I might have mistakenly taken something out.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.