Вот аналогичный подход с чуть меньшим количеством кода, который скрывает курсор и показывает наш собственный курсор, который указывает выбранный пункт меню.
Метод принимает заголовок меню, список опций, которые пользователь может выбрать, и символ курсора.Он печатает заголовок и подчеркивание, а затем каждый параметр с 3 пробелами перед каждым.Затем мы перемещаем курсор к первому варианту (индекс строки 3, так как заголовок равен 0, подчеркивание равно 1, а пробел равен 2), второму символу и пишем символ возврата на одну позицию, за которым следует наш курсор (возврат на клавиатуре стирает первый символ так,мы можем написать новый).
Когда пользователь нажимает клавиши, мы обрабатываем только стрелки вверх и вниз и клавишу ввода.Передав true
в Console.ReadKey()
, пользовательский ввод "отбрасывается" и не отображается в окне.Это позволяет нам switch
только на тех клавишах, которые нам нужны.
Когда они нажимают клавишу со стрелкой, мы перемещаем курсор ко второму столбцу в текущей строке, печатаем пробел, а затем пробел (чтобы стеретьстарый курсор), затем переместитесь вверх или вниз на одну строку, и из второго столбца мы печатаем клавишу возврата и затем наш символ курсора.
Когда пользователь нажимает Enter
, мы снова включаем консольный курсор и возвращаемстрока, в которой находился курсор, чтобы указать, какой элемент был выбран в это время:
private static int GetMenuChoice(string header, List<string> options, char cursor = '>')
{
// Clear console and hide cursor
Console.Clear();
Console.CursorVisible = false;
// Write our header with an underline
Console.WriteLine(" " + header);
Console.WriteLine(" " + new string('-', header.Length));
Console.WriteLine();
// Write out each option with spaces before it
options.ForEach(option => Console.WriteLine($" {option}"));
// Move to the first option and, from the second character,
// write a backspace and then the cursor symbol
Console.SetCursorPosition(1, 3);
Console.Write($"\b{cursor}");
// Move cursor when user presses arrow keys, and get selection when they press enter
while (true)
{
// Pass 'true' to ReadKey so the input is not written
var input = Console.ReadKey(true);
switch (input.Key)
{
case ConsoleKey.UpArrow:
if (Console.CursorTop > 3)
{
Console.CursorLeft = 1;
Console.Write("\b ");
Console.SetCursorPosition(1, Console.CursorTop - 1);
Console.Write($"\b{cursor}");
}
break;
case ConsoleKey.DownArrow:
if (Console.CursorTop < options.Count + 2)
{
Console.CursorLeft = 1;
Console.Write("\b ");
Console.SetCursorPosition(1, Console.CursorTop + 1);
Console.Write($"\b{cursor}");
}
break;
case ConsoleKey.Enter:
var selection = Console.CursorTop - 3;
Console.CursorVisible = true;
Console.SetCursorPosition(0, options.Count + 4);
return selection;
}
}
}
Это можно проверить с помощью образца меню банкомата:
private static void Main()
{
var options = new List<string>
{
"Open a new account",
"Deposit Money",
"Withdraw money",
"Check balance",
"Exit"
};
var selectedItem = GetMenuChoice("ATM Machine", options);
Console.WriteLine($"You selected option: '{options[selectedItem]}'");
GetKeyFromUser("\nDone! Press any key to exit...");
}
Вывод