using System; | |
using System.Threading; | |
static class Program { | |
static void Main() { | |
Console.Write("Performing some task... "); | |
using (var progress = new ProgressBar()) { | |
for (int i = 0; i <= 100; i++) { | |
progress.Report((double) i / 100); | |
Thread.Sleep(20); | |
} | |
} | |
Console.WriteLine("Done."); | |
} | |
} |
using System; | |
using System.Text; | |
using System.Threading; | |
/// <summary> | |
/// An ASCII progress bar | |
/// </summary> | |
public class ProgressBar : IDisposable, IProgress<double> { | |
private const int blockCount = 10; | |
private readonly TimeSpan animationInterval = TimeSpan.FromSeconds(1.0 / 8); | |
private const string animation = @"|/-\"; | |
private readonly Timer timer; | |
private double currentProgress = 0; | |
private string currentText = string.Empty; | |
private bool disposed = false; | |
private int animationIndex = 0; | |
public ProgressBar() { | |
timer = new Timer(TimerHandler); | |
// A progress bar is only for temporary display in a console window. | |
// If the console output is redirected to a file, draw nothing. | |
// Otherwise, we'll end up with a lot of garbage in the target file. | |
if (!Console.IsOutputRedirected) { | |
ResetTimer(); | |
} | |
} | |
public void Report(double value) { | |
// Make sure value is in [0..1] range | |
value = Math.Max(0, Math.Min(1, value)); | |
Interlocked.Exchange(ref currentProgress, value); | |
} | |
private void TimerHandler(object state) { | |
lock (timer) { | |
if (disposed) return; | |
int progressBlockCount = (int) (currentProgress * blockCount); | |
int percent = (int) (currentProgress * 100); | |
string text = string.Format("[{0}{1}] {2,3}% {3}", | |
new string('#', progressBlockCount), new string('-', blockCount - progressBlockCount), | |
percent, | |
animation[animationIndex++ % animation.Length]); | |
UpdateText(text); | |
ResetTimer(); | |
} | |
} | |
private void UpdateText(string text) { | |
// Get length of common portion | |
int commonPrefixLength = 0; | |
int commonLength = Math.Min(currentText.Length, text.Length); | |
while (commonPrefixLength < commonLength && text[commonPrefixLength] == currentText[commonPrefixLength]) { | |
commonPrefixLength++; | |
} | |
// Backtrack to the first differing character | |
StringBuilder outputBuilder = new StringBuilder(); | |
outputBuilder.Append('\b', currentText.Length - commonPrefixLength); | |
// Output new suffix | |
outputBuilder.Append(text.Substring(commonPrefixLength)); | |
// If the new text is shorter than the old one: delete overlapping characters | |
int overlapCount = currentText.Length - text.Length; | |
if (overlapCount > 0) { | |
outputBuilder.Append(' ', overlapCount); | |
outputBuilder.Append('\b', overlapCount); | |
} | |
Console.Write(outputBuilder); | |
currentText = text; | |
} | |
private void ResetTimer() { | |
timer.Change(animationInterval, TimeSpan.FromMilliseconds(-1)); | |
} | |
public void Dispose() { | |
lock (timer) { | |
disposed = true; | |
UpdateText(string.Empty); | |
} | |
} | |
} |
This comment has been minimized.
This comment has been minimized.
|
This comment has been minimized.
This comment has been minimized.
This dosnt work on .net core 1.0. Something to do with the new Timer(...) error |
This comment has been minimized.
This comment has been minimized.
Awesome. thanks you! |
This comment has been minimized.
This comment has been minimized.
|
This comment has been minimized.
This comment has been minimized.
thx for the stuff |
This comment has been minimized.
This comment has been minimized.
Great thank you for sharing this :D |
This comment has been minimized.
This comment has been minimized.
awesome , how about a panel ? |
This comment has been minimized.
This comment has been minimized.
Awesome! |
This comment has been minimized.
This comment has been minimized.
Great job ! |
This comment has been minimized.
This comment has been minimized.
thanks |
This comment has been minimized.
This comment has been minimized.
@ernest-galbrun |
This comment has been minimized.
This comment has been minimized.
Awesome! |
This comment has been minimized.
This comment has been minimized.
Great Job, Thanks ! |
This comment has been minimized.
This comment has been minimized.
awesome. Thanks for sharing. |
This comment has been minimized.
This comment has been minimized.
What about multiple async progress bars in the console? |
This comment has been minimized.
This comment has been minimized.
I'm just here for the animation at the end uwu |
This comment has been minimized.
This comment has been minimized.
Very nice and thanks for sharing! Timer doesn't work under .Net Core. To make work, change it to:
|
This comment has been minimized.
This comment has been minimized.
Great! Thank you! |
This comment has been minimized.
This comment has been minimized.
Great, Thanks! |
This comment has been minimized.
This comment has been minimized.
Thanks for this, it's great, I added a function to allow writes to console:
|
This comment has been minimized.
This comment has been minimized.
I am downloading a file via sftp and a C# console app. How can I use this to display a progress bar to the user in the console app? I do not understand how it reports progress??? |
This comment has been minimized.
This comment has been minimized.
Beautiful, works like charm. |
This comment has been minimized.
This comment has been minimized.
Love it! |
This comment has been minimized.
This comment has been minimized.
excellent, thank you so much |
This comment has been minimized.
This comment has been minimized.
Amazing ! Thank you! |
This comment has been minimized.
This comment has been minimized.
thanks you |
This comment has been minimized.
This comment has been minimized.
Hello, I have a question.
Or it it done by setting disposed = true ? |
This comment has been minimized.
This comment has been minimized.
Does this work with console logging? Or do I lose them... |
This comment has been minimized.
This comment has been minimized.
@ssinfod Sorry for the late reply. Yes, disposing the timer after the |
This comment has been minimized.
This comment has been minimized.
I've added an answer to your SO question. I hope that explains it. |
This comment has been minimized.
This comment has been minimized.
Noice. |
This comment has been minimized.
This comment has been minimized.
That's perfect and saving me a lot of time, thank you!! |
This comment has been minimized.
This comment has been minimized.
Awesome! |
This comment has been minimized.
This comment has been minimized.
Awesome, thanks for sharing! |
This comment has been minimized.
This comment has been minimized.
Man I loved it. That's so dope! |
This comment has been minimized.
This comment has been minimized.
Thanks! |
This comment has been minimized.
This comment has been minimized.
awesome! |
This comment has been minimized.
This comment has been minimized.
Awesome stuff!!! Thank you |
This comment has been minimized.
This comment has been minimized.
In production code, it only go to 90% oftenly , how can i fix it. |
This comment has been minimized.
This comment has been minimized.
Thanks a lot. |
This comment has been minimized.
This comment has been minimized.
Check that you actually report a value larger than 0.9. Also, do you dispose the progress bar (either by calling |
This comment has been minimized.
Awesome stuff👍