Консольное приложение: как обновить дисплей без мерцания?

Использование С# 4 в консольном приложении Windows, которое постоянно сообщает о прогрессе, как я могу сделать "перерисовку" экрана более жидким?

Я хотел бы сделать одно из следующего:  - Имейте только "перерисовку" той части экрана, которая изменяется (часть прогресса), и оставляйте остальное как есть.  - "Перерисовать" весь экран, но не мигать.

В настоящее время я переписываю весь текст (имя приложения и т.д.). Вот так:

Console.Clear();
WriteTitle();
Console.WriteLine();
Console.WriteLine("Deleting:\t{0} of {1} ({2})".FormatString(count.ToString("N0"), total.ToString("N0"), (count / (decimal)total).ToString("P2")));

Это вызывает много мерцания.

Ответ 2

Я знаю, что этот вопрос немного устарел, но я обнаружил, что если вы установите Console.CursorVisible = false, то мерцание также прекратится.

Ответ 3

static void Main(string[] args)
{
    Console.SetCursorPosition(0, 0);
    Console.Write("################################");
    for (int row = 1; row < 10; row++)
    {
        Console.SetCursorPosition(0, row);
        Console.Write("#                              #");
    }
    Console.SetCursorPosition(0, 10);
    Console.Write("################################");

    int data = 1;
    System.Diagnostics.Stopwatch clock = new System.Diagnostics.Stopwatch();
    clock.Start();
    while (true)
    {
        data++;
        Console.SetCursorPosition(1, 2);
        Console.Write("Current Value: " + data.ToString());
        Console.SetCursorPosition(1, 3);
        Console.Write("Running Time: " + clock.Elapsed.TotalSeconds.ToString());
        Thread.Sleep(1000);
    }

    Console.ReadKey();
}

Ответ 4

Вы можете попытаться взломать что-то вместе, используя основные библиотеки.

Вместо того, чтобы тратить время на получение нестандартных результатов, я бы посмотрел этот порт С# библиотеки ncurses (которая является библиотекой, используемой для вывода консольного форматирования):

Curses Sharp

Ответ 5

Я думаю, вы можете использовать \r в консоли Windows, чтобы вернуть начало строки. Вы также можете использовать SetCursorPosition.

Ответ 6

Вот простая рабочая демонстрация, показывающая многострочное использование без мерцания. Он показывает текущее время и случайную строку каждую секунду.

    private static void StatusUpdate()
    {
        var whiteSpace = new StringBuilder();
        whiteSpace.Append(' ', 10);
        var random = new Random();
        const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        var randomWord = new string(Enumerable.Repeat(chars, random.Next(10)).Select(s => s[random.Next(s.Length)]).ToArray());
        while (true)
        {
            Console.SetCursorPosition(0, 0);
            var sb = new StringBuilder();
            sb.AppendLine($"Program Status:{whiteSpace}");
            sb.AppendLine("-------------------------------");
            sb.AppendLine($"Last Updated: {DateTime.Now}{whiteSpace}");
            sb.AppendLine($"Random Word: {randomWord}{whiteSpace}");
            sb.AppendLine("-------------------------------");
            Console.Write(sb);
            Thread.Sleep(1000);
        }
    }

В приведенном выше примере предполагается, что окно консоли пуста для запуска. Если нет, обязательно используйте Console.Clear().

Техническое примечание: SetCursorPosition (0,0) помещает курсор в начало (0,0), поэтому следующий вызов Console.Write начнется с строки 0, char 0. Обратите внимание: он не удаляет предыдущее содержимое перед записью. В качестве примера, если вы напишете "asdf" по предыдущей строке, например "0123456", в итоге вы получите что-то вроде "asdf456". По этой причине мы используем переменную whiteSpace, чтобы гарантировать, что любые затяжные символы из предыдущей строки будут перезаписаны пустым пространством. Отрегулируйте длину переменной whiteSpace в соответствии с вашими потребностями. Вам нужна только переменная whiteSpace для строк, которые меняются.

Личное примечание: Для моих целей я хотел показать текущее состояние приложений (один раз в секунду) вместе с кучей другой информации о статусе, и я хотел избежать любого раздражающего мерцания, которое может произойти, когда вы используете Console.Clear(). В моем приложении я запускаю свои обновления статуса за отдельным потоком, поэтому он постоянно предоставляет обновления, даже если у меня есть много других потоков и длительных задач, идущих одновременно.

Кредиты: Благодаря предыдущим плакатам и dtb для генератора случайных строк, используемых в демо. Как я могу генерировать случайные буквенно-цифровые строки в С#?