Как записать символ в консоль не передвигая курсор?

Есть код:

Console.SetBufferSize(Console.WindowWidth, Console.WindowHeight);

Console.Write("╔");
for (int i = 0; i < Console.WindowWidth - 2; i++)
    Console.Write("═");
Console.Write("╗");

for(int i = 0; i < Console.WindowHeight - 2; i++)
{
    Console.Write("║");
    for (int j = 0; j < Console.WindowWidth - 2; j++)
        Console.Write(" ");
    Console.Write("║");
}

Console.Write("╚");
for (int i = 0; i < Console.WindowWidth - 2; i++)
    Console.Write("═");
Console.Write("╝");

Которая должна выводить рамку в консоль, но первая строка стирается т.к. происходит переход на следующую строку:

Как убрать этот переход, чтобы было так, но с символом "╝" в конце:


Ответы (1 шт):

Автор решения: aepot

Класс Console не представляет такой возможности, поэтому потребуется использовать Win API. Я нашел метод kernel32.dll - WriteConsoleOutputCharacter.

Для того чтобы им воспользоваться, написал вот такой класс.

public static class ConsoleHelper
{
    [DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
    private static extern bool WriteConsoleOutputCharacter(IntPtr hConsoleOutput, string lpCharacter, uint nLength, Point16 dwWriteCoord, out uint lpNumberOfCharsWritten);
    [DllImport("kernel32.dll")]
    private static extern IntPtr GetStdHandle(int nStdHandle);

    private const int STD_OUTPUT_HANDLE = -11;
    private const int STD_INPUT_HANDLE = -10;
    private const int STD_ERROR_HANDLE = -12;
    private static readonly IntPtr _stdOut = GetStdHandle(STD_OUTPUT_HANDLE);

    [StructLayout(LayoutKind.Sequential)]
    private struct Point16
    {
        public short X;
        public short Y;

        public Point16(short x, short y)
            => (X, Y) = (x, y);
    };

    public static void WriteToBufferAt(string text, int x, int y)
    {
        WriteConsoleOutputCharacter(_stdOut, text, (uint)text.Length, new Point16((short)x, (short)y), out uint _);
    }
}

По сути метод WriteToBufferAt пишет текст в консоль по указанным координатам, и при этом никак не двигает курсор.

Ваш код немного упростил, потому что вы делали очень много вызовов записи в консоль, а это медленно.

class Program
{
    static void Main(string[] args)
    {
        Console.SetBufferSize(Console.WindowWidth, Console.WindowHeight);
        Console.Write("╔");
        Console.Write(new string('═', Console.WindowWidth - 2));
        Console.Write("╗");

        for (int i = 0; i < Console.WindowHeight - 2; i++)
        {
            Console.Write("║");
            Console.Write(new string(' ', Console.WindowWidth - 2));
            Console.Write("║");
        }

        Console.Write("╚");
        Console.Write(new string('═', Console.WindowWidth - 2));
        ConsoleHelper.WriteToBufferAt("╝", Console.WindowWidth - 1, Console.WindowHeight - 1);
        Console.ReadKey(true);
    }
}

введите сюда описание изображения

А вообще можно сократить количество записей в консоль до одного вызова.

static void Main(string[] args)
{
    Console.SetBufferSize(Console.WindowWidth, Console.WindowHeight);
    StringBuilder sb = new StringBuilder();
    string hRow = new string('═', Console.WindowWidth - 2);
    string blankRow = new string(' ', Console.WindowWidth - 2);
    sb.Append('╔').Append(hRow).Append('╗');

    for (int i = 0; i < Console.WindowHeight - 2; i++)
    {
        sb.Append('║').Append(blankRow).Append('║');
    }

    sb.Append('╚').Append(hRow).Append('╝');
    ConsoleHelper.WriteToBufferAt(sb.ToString(), 0, 0);
    Console.ReadKey(true);
}

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

Console.ForegroundColor = ConsoleColor.Green;
Console.Clear();
→ Ссылка