The ConsoleTextFormat package includes the Layout class in which there are methods that enable the use of a menu for selection from a list. The list can be a list of strings, be generated from an enum type or just be a range of integers. Some examples: …

The Nuget ConsoleTextFormat package was developed to provide some textual formatting for the Console app in Softata as on GitHub here djaus2/Softata/SoftataConsole

In the previous post, the Layout class contained a hierarchy of menu methods:

  • SelectEnum<T>() which calls …
  • DisplayMenu() which calls …
  • Prompt4Num()

The second method displays the menu from a list of string and calls the third to get the user’s selection as a valid key. The first method calls the second using a list of strings generated from the enum’s names.

Prompt4Num() takes a max value and a default value in the range 1 … max. A valid response is in that range. ‘Q’ or ‘q’ can alternatively be pressed in which case -1 is the returned value. This method can be used directly without a menu if an actual number in a ange from 1 is what is required.

A List of String Menu Example

A list of strings is supplied for the user to select from. The index of the selected item in the list (from 0) is returned. Items are displayed with a key to press (from 1). So the user can select by pressing '1' ... '9'. Where more than 9 items are in the list, keys from 'A' are used.
In this example, menu the user selects a Serial Loopback test. Note that in this version a valid number is entered then [Enter] is pressed.
    Console.WriteLine("Serial Test");
    Console.WriteLine("1. Serial 1");
    Console.WriteLine("2. Serial 2");
    Console.WriteLine("3. (Tx)Serial 1 -> (Rx)Serial 2");
    Console.WriteLine("4. (Tx)Serial 2 -> (Rx)Serial 1");
    Console.WriteLine("5. Quit");
    Console.Write("Selection:");
    bool serialFound = false;
    byte iserialTxRx = 1;
    do
    {
        string? s = Console.ReadLine();
        if (byte.TryParse(s, out byte numTxRx))
        {
            if ((numTxRx > 0) && (numTxRx <= 5))
            {
                serialFound = true;
                iserialTxRx = numTxRx;
            }
        }
        else if (!string.IsNullOrEmpty(s))
        {
            string key = s;
            if (key.ToUpper() == "Q")
            {
                iserialTxRx = 5;
                serialFound = true;
            }
        }
    } while (!serialFound);

    if (iserialTxRx == 5)
        break;

becomes …

Note in this version, the user similarly enters a number by key press only, no [Return] required. DisplayMenu() returns a valid number (0 ... 3 in this case) ... the key pressed, unless the key is 'Q'/'q' in which case -1 is returned.
Note that whilst the displayed menu uses index (and keys ) 1 ... 4, the returned values are 0 ...3 and so that the list item can be accessed such as SerialMenu[iserialTxRx].
    Layout.Heading("Serial Test");
    Layout.Info("\nSelect Test");
    List<string> SerialMenu = new List<string> { "Serial 1", "Serial 2", "Serial 1 -> Serial 2", "Serial 2 -> Serial 1" };
    int serialMenuChoice = (byte)Layout.DisplayMenu(1, SerialMenu, true);
    if (serialMenuChoice < 0)
        break;
    byte iserialTxRx =  (byte)(1+serialMenuChoice);

Shorter, neater and extensible!

An Enum Menu Example

Given an enum data type, as a list of ordinals, display the list with a key for each for selection. Return the selected enum value.
In this example, the user selects a ConsoleTestType as enumerated. The returned value is the enum value, not its index in the list.
public enum ConsoleTestType : byte
{
    Digital_Button_and_LED = 0,
    Analog_Potentiometer_and_LED = 1,
    PWM = 2,
    ...
    etc.
}
    ConsoleTestType Testtype = (ConsoleTestType) 0;
    for (int i = 0; i < (int)ConsoleTestType.MaxType; i++)
    {
        num++;
        ConsoleTestType cmd = (ConsoleTestType)i;
        string msg = $"{i + 1}.\t\t{cmd}";
        msg = msg.Replace("_", " ");
        Console.WriteLine(msg);
    }
    Console.WriteLine("[Q]\t\tQuit");
    Console.WriteLine();
    Console.Write($"Please make a selection (Default is {(int)Testtype + 1}):");
    bool foundTestType = false;
    do
    {
        string? s = Console.ReadLine();
        if (string.IsNullOrEmpty(s))
            break;
        if (byte.TryParse(s, out byte icmd))
        {
            if (icmd > 0 && icmd <= num)
            {
                Testtype = (ConsoleTestType)(icmd - 1);
                foundTestType = true;
            }
        }
        else if (s.ToUpper() == "Q")
        {
            foundTestType = true;
            quit = true;
        }
    } while (!foundTestType);
    if (quit)
        return;

reduces to:

    Layout.Info("Select Test Type");
    ConsoleTestType Testtype = Layout.SelectEnum<ConsoleTestType>((int)Testtype + 1, ref quit, true);
    if (quit)
        return;

Isn’t that simpler?

Addendum

With the menus, Q or q can be pressed to indicate Quit. This is an optional parameter with the menu methods which is by default false. If the methods' parameter quit is true then quit becomes an option. At the lowest level Prompt4Ch() returns Q to indicate quit has been selected. At the next level Prompt4Num() then passes back -1 for that. DisplayMenu passes that back (it only orchestrates the menu functionality). SelectEnum() which calls DisplayMenu then casts the returned value (if not -1) to the enum. If -1 is passed back to it, a default enum value is returned but a reference parameter to it Quit is passed back by it as true (false otherwise).
So SelectEnum() has two parameters named "quit". The completely lowercase one, quit is of type bool indicating whether quit is an option for the menu. The one with the leading uppercase Q Quit is the referenced parameter.
 T SelectEnum<T>(int defaultOrdinal, ref bool Quit, bool quit = false)

The SelectEnum() parameters.

Conclusion

The ConsoleTextFormat package includes the Layout class in which there are methods that enable the use of a menu for selection from a list. The list can be a list a of strings, an enum type from which a list is generated or simply be a range oof integers from 1 to a maximum values. These enable the simple presentation of a menu in a .NET Console app.


 TopicSubtopic
   
 This Category Links 
Category:Coding Index:Coding
<  Prev:   ConsoleTextFormat