Search code examples
c#user-interfacemenuconsole-application

C# Console app - How do I make an interactive menu?


I'm trying to make a menu that looks similar to:

> Thing
  Another Thing
  Yet Another Thing
  Exit

Within a C# console app. I've looked all over but can't find a library/example code for this sort of menu.

Put simply, i want to...

  1. Display a menu
  2. Allow the user to make a selection using the arrow keys [UP/DOWN]
  3. Do different things when different options are selected [Enter]

Solution

  • Main thing is to be able to capture inputs. Console can only "simulate" an interactive menu by clearing the console window and re-rendering it again.

    using System.Collections.Generic;
    using System;
    using System.Linq;
    using System.Threading;
    
    namespace ConsoleApp
    {
        class Program
        {
            public static List<Option> options;
            static void Main(string[] args)
            {
                // Create options that you want your menu to have
                options = new List<Option>
                {
                    new Option("Thing", () => WriteTemporaryMessage("Hi")),
                    new Option("Another Thing", () =>  WriteTemporaryMessage("How Are You")),
                    new Option("Yet Another Thing", () =>  WriteTemporaryMessage("Today")),
                    new Option("Exit", () => Environment.Exit(0)),
                };
    
                // Set the default index of the selected item to be the first
                int index = 0;
    
                // Write the menu out
                WriteMenu(options, options[index]);
    
                // Store key info in here
                ConsoleKeyInfo keyinfo;
                do
                {
                    keyinfo = Console.ReadKey();
    
                    // Handle each key input (down arrow will write the menu again with a different selected item)
                    if (keyinfo.Key == ConsoleKey.DownArrow)
                    {
                        if (index + 1 < options.Count)
                        {
                            index++;
                            WriteMenu(options, options[index]);
                        }
                    }
                    if (keyinfo.Key == ConsoleKey.UpArrow)
                    {
                        if (index - 1 >= 0)
                        {
                            index--;
                            WriteMenu(options, options[index]);
                        }
                    }
                    // Handle different action for the option
                    if (keyinfo.Key == ConsoleKey.Enter)
                    {
                        options[index].Selected.Invoke();
                        index = 0;
                    }
                }
                while (keyinfo.Key != ConsoleKey.X);
    
                Console.ReadKey();
    
            }
            // Default action of all the options. You can create more methods
            static void WriteTemporaryMessage(string message)
            {
                Console.Clear();
                Console.WriteLine(message);
                Thread.Sleep(3000);
                WriteMenu(options, options.First());
            }
    
    
    
            static void WriteMenu(List<Option> options, Option selectedOption)
            {
                Console.Clear();
    
                foreach (Option option in options)
                {
                    if (option == selectedOption)
                    {
                        Console.Write("> ");
                    }
                    else
                    {
                        Console.Write(" ");
                    }
    
                    Console.WriteLine(option.Name);
                }
            }
        }
    
        public class Option
        {
            public string Name { get; }
            public Action Selected { get; }
    
            public Option(string name, Action selected)
            {
                Name = name;
                Selected = selected;
            }
        }
    
    }