Open Dangelo123 opened 7 years ago
looking into this now, thank you for the gif, that is most helpful.
if I understand the problem it can be described as follows
// progressbars should not stop the screen from being scrolled
given more progressbars than the height of the console window
when the user scrolls to the top of the console window causing content to scroll off the bottom
and the progressbars are refreshed or updated
then the scroll position should remain at the top of the screen
when the user scrolls to the middle of the content height causing content to hidden from the top and the bottom of the console window
and the progressbars are refreshed or updated
then the scroll position should remain in the middle of the screen
when the user scrolls to the bottom of the content causing content to scrolled off (clipped) from the top of the console window
and the progressbars are refreshed or updated
then the scroll position should remain at the bottom of the screen
Perfect, that's right!
I'm sorry if my writing early was a little bit confusing, english is not my mother language. If you need any more further clarification feel free to ask me
ok, spent a bit of time looking into this, and it's a trickly one indeed. The issue is cause (i think) by the work I did to make sure the progress bar is threadsafe, specifically this bit of code
lock (_locker)
{
_item = item;
var state = _console.State;
_current = current.Max(Max);
try
{
float perc = (float) _current/(float) _max;
int barWidth = _console.WindowWidth - (TextWidth+8);
var bar = _current > 0
? new string(_character, (int) ((float) (barWidth)*perc)).PadRight(barWidth)
: new string(' ', barWidth);
var text = string.Format("{0} ({1,-3}%) ", clippedText, (int) (perc*100));
_console.CursorTop = _y;
_console.CursorLeft = 0;
_console.ForegroundColor = _c;
_console.Write(text);
_console.ForegroundColor = ConsoleColor.Green;
_console.Write(bar);
_line = $"{text} {bar}";
}
finally
{
_console.State = state;
}
}
The responsibility in the code above that causes the issue is that the lock is held on the progressbar in order to reset
the state, including the cursor positions, left and top, so that if any other thread writes to any window
or console
or via the .net Console
class, that the position is correct.
What happens as a result, is that in your demo, and what I've managed to reproduce, if you have hundreds of progress bars, (e.g. 1 per file with hundreds of files), then when you click to drag the console window, the click and drag takes a very long time by pc standards, and during the 'dragging' of the scrollbar, there's about 5 or 6 cusor top and left's being set.
The only-ish solution that I can think of right now would require writing directly to the low level windows buffer, and-or disabling scrolling while you're dragging, and then re-enabling it after you let go. Something that's out of scope of any reasonable return on effort for an open source project.
Also, I think the use case of hundreds of progress-bars, makes for an unusable experience for the user, and results in a too-much information.
WorkAround
Displaying the progress of the total number of files in a collection, using the two-line ProgressBar
instead of ProgressBarSlim
would make much more sense, imho, and result in much fewer writes per second, allowing for easy dragging of the scrollbar if needed.
Also, the user would be able to more easily see at a glance more useful information e.g. total number of wav files, background images, or sprites, etc. Write a complete text logfile of the actual files downloaded, _log.Info('starting downloading x'); _log.Info('finished downloading x');
and update the high level summary progresses using ProgressBar
instead of relying on outputting detailed logging to the console.
If you can let me know exactly why you need to have so many progressbars, then I'll consider alternatives and-or re-open this issue. In the meantime closing this, if you agree. ;)
cheers,
Alan
Thank you for you time looking at the issue.
Before I opened the issue I also took a look in the code myself, and based in the little that I've learned I agree with your statements. But I consider my motivation to use a few dozens of bars, in the most, 50-60, a valid one. It's not like a crucial functionality, more like a bonus to the user. My application is based on Entities, and each entity has 'n' validations. Each validation is a complex and independent operation that reads and write thousands of data in the database. I could simply display Entities, and hide validations (and that is probably what I'm going to do right now), but for the user it's simply better to have the complete picture of the progress.
Again, thanxs for the feedback and of course for the useful library! If someday I reach a viable solution I'll surely post here, but for now, you can close the issue.
Silly question, but have you tried increasing the height of the default console window? Or tried splitting the window into two, left and right?
for example: I created this sample with 60 progress bars avoiding scrolling (code below the screenshot)
private static void SixtyProgressBars()
{
var con = new Window();
var left = con.SplitLeft("Entities");
var right = con.SplitRight("Validations");
var t1 = Task.Run(()=> DoTheThingToTheDbWithTheStuff(left, 30));
var t2 = Task.Run(() => DoTheThingToTheDbWithTheStuff(right, 30));
Task.WaitAll(t1, t2);
Console.WriteLine("All done");
}
private static void DoTheThingToTheDbWithTheStuff(IConsole window, int cnt)
{
var r = new Random();
var pbs = Enumerable.Range(1, cnt).Select(i =>
{
var pb = new ProgressBar(window, r.Next(200) + 1);
pb.Refresh(1, TestData.RandomName);
return pb;
}).ToArray();
for (int i = 0; i < cnt * 100; i++)
{
Thread.Sleep(r.Next(200));
i = r.Next(cnt);
var pb = pbs[i];
if(pb.Current<100) pb.Next(TestData.RandomName);
}
}
Hi,
When there are many progressBars, so you cant see all the info and bars in the window, the cursor keeps refreshing on the bottom of console, causing the scroll to be stuck there in way we cannot scroll back up.
The behavior is recorded on the gif below
http://gph.is/2vGsKSU