Pueden darme consejos de cómo lo harían ustedes.
Yo quizás lo hiciese de la siguiente manera...
Por un lado una Class para definir un item de menu:
''' <summary>
''' Defines a Console Menu Item.
''' </summary>
Public NotInheritable Class ConsoleMenuItem
''' <summary>
''' Gets or sets the item text.
''' </summary>
''' <value>The item text.</value>
Public Property Text As String
''' <summary>
''' Gets or sets the <see cref="ConsoleKey"/> that activates this item.
''' </summary>
''' <value>The <see cref="ConsoleKey"/> that activates this item.</value>
Public Property Key As ConsoleKey
''' <summary>
''' Gets or sets the associated <see cref="Command"/> for this item.
''' </summary>
''' <value>The associated <see cref="Command"/> for this item.</value>
Public Property Command As Action
End Class
Con ello, compongo los items del menú y sub-menúes:
''' <summary>
''' The main menu items.
''' </summary>
Private ReadOnly mainMenuItems As IEnumerable(Of ConsoleMenuItem) =
{
New ConsoleMenuItem With
{
.Text = "[1] Show first submenu",
.Key = ConsoleKey.D1,
.Command = New Action(Sub()
ShowMenu(subMenuItems1)
End Sub)
},
New ConsoleMenuItem With
{
.Text = "[2] Show second submenu",
.Key = ConsoleKey.D2,
.Command = New Action(Sub()
ShowMenu(subMenuItems2)
End Sub)},
menuItemExit
}
''' <summary>
''' The first submenu items.
''' </summary>
Private ReadOnly subMenuItems1 As IEnumerable(Of ConsoleMenuItem) =
{
New ConsoleMenuItem With
{
.Text = "[1] Print a 'Hello World!'",
.Key = ConsoleKey.D1,
.Command = New Action(Sub()
Console.WriteLine("Hello World!")
End Sub)
},
New ConsoleMenuItem With
{
.Text = "[R] Return",
.Key = ConsoleKey.R,
.Command = New Action(Sub()
ShowMenu(mainMenuItems)
End Sub)},
menuItemExit
}
''' <summary>
''' The second submenu items.
''' </summary>
Private ReadOnly subMenuItems2 As IEnumerable(Of ConsoleMenuItem) =
{
New ConsoleMenuItem With
{
.Text = "[1] Print the current date.",
.Key = ConsoleKey.D1,
.Command = Sub()
Console.WriteLine(Date.Today.ToLongDateString)
End Sub
},
New ConsoleMenuItem With
{
.Text = "[R] Return",
.Key = ConsoleKey.R,
.Command = New Action(Sub()
ShowMenu(mainMenuItems)
End Sub)},
menuItemExit
}
''' <summary>
''' A menu item that exists from console.
''' </summary>
Private ReadOnly menuItemExit As New ConsoleMenuItem With
{
.Text = "[X] Exit...",
.Key = ConsoleKey.X,
.Command = AddressOf EndConsole
}
El resto ya solo es darle el formato de texto deseado al menú, y procesar la entrada del teclado:
''' <summary>
''' Defines the entry point of the application.
''' </summary>
Public Sub Main()
ShowMenu(mainMenuItems)
System.Threading.Thread.Sleep(Integer.MaxValue)
End Sub
''' <summary>
''' Shows a console menu.
''' </summary>
''' <param name="menuItems">The items that composes the menu.</param>
''' <param name="itemIndicator">A string that indicates the current menu item.</param>
Private Sub ShowMenu(ByVal menuItems As IEnumerable(Of ConsoleMenuItem),
Optional ByVal itemIndicator As String = " -> ")
' The selected menu item.
Dim selectedItem As ConsoleMenuItem = menuItems(0)
' The index of the selected menu item.
Dim selectedIndex As Integer
' The object to read the user-input pressed key.
Dim currentKey As ConsoleKey
' Flag that determines wether the user pressed a valid menu item key.
Dim itemKeyIsPressed As Boolean
' Wait for a valid menu item key.
Do Until itemKeyIsPressed
' Iterate the menu items to format the menu string.
Dim sb As New System.Text.StringBuilder
With sb
sb.AppendLine("===============================")
sb.AppendLine("=========== My Menu ===========")
sb.AppendLine("===============================")
sb.AppendLine()
For Each menuItem As ConsoleMenuItem In menuItems
If menuItem Is selectedItem Then
sb.AppendLine(String.Format("{0}{1}", itemIndicator, menuItem.Text))
Else
sb.AppendLine(menuItem.Text.Insert(0, New String(" "c, itemIndicator.Length)))
End If
Next menuItem
sb.AppendLine()
sb.AppendLine("===============================")
End With
' Clear the screen.
Console.Clear()
' Print the menu items.
Console.WriteLine(sb.ToString)
' Wait for user-input.
currentKey = Console.ReadKey(True).Key
' Handle the pressed key.
Select Case currentKey
Case ConsoleKey.DownArrow ' Decrease current item selection.
selectedIndex = menuItems.ToList.IndexOf(selectedItem)
If selectedIndex < (menuItems.Count - 1) Then
selectedItem = menuItems(selectedIndex + 1)
Else
selectedItem = menuItems.First
End If
Case ConsoleKey.UpArrow ' Increase current item selection.
selectedIndex = menuItems.ToList.IndexOf(selectedItem)
If selectedIndex <> 0 Then
selectedItem = menuItems(selectedIndex - 1)
Else
selectedItem = menuItems.Last
End If
Case ConsoleKey.Enter ' Run the selected item's command.
itemKeyIsPressed = True
selectedItem.Command.Invoke()
Case ConsoleKey.Backspace ' Return to previous menu (if any).
Dim foundItem As ConsoleMenuItem =
(From item As ConsoleMenuItem In menuItems
Where item.Key = ConsoleKey.R).FirstOrDefault
If foundItem IsNot Nothing Then
itemKeyIsPressed = True
selectedItem = foundItem
selectedItem.Command.Invoke()
End If
Case Else
Dim foundItem As ConsoleMenuItem =
(From item As ConsoleMenuItem In menuItems
Where item.Key = currentKey).FirstOrDefault
If foundItem IsNot Nothing Then
itemKeyIsPressed = True
selectedItem = foundItem
selectedItem.Command.Invoke()
End If
End Select
Loop
End Sub
''' <summary>
''' Terminates the application.
''' </summary>
Private Sub EndConsole()
Environment.Exit(exitCode:=0)
End Sub
El source completo, en VB:
Module Module1
''' <summary>
''' Defines a Console Menu Item.
''' </summary>
Public NotInheritable Class ConsoleMenuItem
''' <summary>
''' Gets or sets the item text.
''' </summary>
''' <value>The item text.</value>
Public Property Text As String
''' <summary>
''' Gets or sets the <see cref="ConsoleKey"/> that activates this item.
''' </summary>
''' <value>The <see cref="ConsoleKey"/> that activates this item.</value>
Public Property Key As ConsoleKey
''' <summary>
''' Gets or sets the associated <see cref="Command"/> for this item.
''' </summary>
''' <value>The associated <see cref="Command"/> for this item.</value>
Public Property Command As Action
End Class
''' <summary>
''' A menu item that exists from console.
''' </summary>
Private ReadOnly menuItemExit As New ConsoleMenuItem With
{
.Text = "[X] Exit...",
.Key = ConsoleKey.X,
.Command = AddressOf EndConsole
}
''' <summary>
''' The main menu items.
''' </summary>
Private ReadOnly mainMenuItems As IEnumerable(Of ConsoleMenuItem) =
{
New ConsoleMenuItem With
{
.Text = "[1] Show first submenu",
.Key = ConsoleKey.D1,
.Command = New Action(Sub()
ShowMenu(subMenuItems1)
End Sub)
},
New ConsoleMenuItem With
{
.Text = "[2] Show second submenu",
.Key = ConsoleKey.D2,
.Command = New Action(Sub()
ShowMenu(subMenuItems2)
End Sub)},
menuItemExit
}
''' <summary>
''' The first submenu items.
''' </summary>
Private ReadOnly subMenuItems1 As IEnumerable(Of ConsoleMenuItem) =
{
New ConsoleMenuItem With
{
.Text = "[1] Print a 'Hello World!'",
.Key = ConsoleKey.D1,
.Command = New Action(Sub()
Console.WriteLine("Hello World!")
End Sub)
},
New ConsoleMenuItem With
{
.Text = "[R] Return",
.Key = ConsoleKey.R,
.Command = New Action(Sub()
ShowMenu(mainMenuItems)
End Sub)},
menuItemExit
}
''' <summary>
''' The second submenu items.
''' </summary>
Private ReadOnly subMenuItems2 As IEnumerable(Of ConsoleMenuItem) =
{
New ConsoleMenuItem With
{
.Text = "[1] Print the current date.",
.Key = ConsoleKey.D1,
.Command = Sub()
Console.WriteLine(Date.Today.ToLongDateString)
End Sub
},
New ConsoleMenuItem With
{
.Text = "[R] Return",
.Key = ConsoleKey.R,
.Command = New Action(Sub()
ShowMenu(mainMenuItems)
End Sub)},
menuItemExit
}
''' <summary>
''' Defines the entry point of the application.
''' </summary>
Public Sub Main()
ShowMenu(mainMenuItems)
System.Threading.Thread.Sleep(Integer.MaxValue)
End Sub
''' <summary>
''' Shows a console menu.
''' </summary>
''' <param name="menuItems">The items that composes the menu.</param>
''' <param name="itemIndicator">A string that indicates the current menu item.</param>
Private Sub ShowMenu(ByVal menuItems As IEnumerable(Of ConsoleMenuItem),
Optional ByVal itemIndicator As String = " -> ")
' The selected menu item.
Dim selectedItem As ConsoleMenuItem = menuItems(0)
' The index of the selected menu item.
Dim selectedIndex As Integer
' The object to read the user-input pressed key.
Dim currentKey As ConsoleKey
' Flag that determines wether the user pressed a valid menu item key.
Dim itemKeyIsPressed As Boolean
' Wait for a valid menu item key.
Do Until itemKeyIsPressed
' Iterate the menu items to format the menu string.
Dim sb As New System.Text.StringBuilder
With sb
sb.AppendLine("===============================")
sb.AppendLine("=========== My Menu ===========")
sb.AppendLine("===============================")
sb.AppendLine()
For Each menuItem As ConsoleMenuItem In menuItems
If menuItem Is selectedItem Then
sb.AppendLine(String.Format("{0}{1}", itemIndicator, menuItem.Text))
Else
sb.AppendLine(menuItem.Text.Insert(0, New String(" "c, itemIndicator.Length)))
End If
Next menuItem
sb.AppendLine()
sb.AppendLine("===============================")
End With
' Clear the screen.
Console.Clear()
' Print the menu items.
Console.WriteLine(sb.ToString)
' Wait for user-input.
currentKey = Console.ReadKey(True).Key
' Handle the pressed key.
Select Case currentKey
Case ConsoleKey.DownArrow ' Decrease current item selection.
selectedIndex = menuItems.ToList.IndexOf(selectedItem)
If selectedIndex < (menuItems.Count - 1) Then
selectedItem = menuItems(selectedIndex + 1)
Else
selectedItem = menuItems.First
End If
Case ConsoleKey.UpArrow ' Increase current item selection.
selectedIndex = menuItems.ToList.IndexOf(selectedItem)
If selectedIndex <> 0 Then
selectedItem = menuItems(selectedIndex - 1)
Else
selectedItem = menuItems.Last
End If
Case ConsoleKey.Enter ' Run the selected item's command.
itemKeyIsPressed = True
selectedItem.Command.Invoke()
Case ConsoleKey.Backspace ' Return to previous menu (if any).
Dim foundItem As ConsoleMenuItem =
(From item As ConsoleMenuItem In menuItems
Where item.Key = ConsoleKey.R).FirstOrDefault
If foundItem IsNot Nothing Then
itemKeyIsPressed = True
selectedItem = foundItem
selectedItem.Command.Invoke()
End If
Case Else
Dim foundItem As ConsoleMenuItem =
(From item As ConsoleMenuItem In menuItems
Where item.Key = currentKey).FirstOrDefault
If foundItem IsNot Nothing Then
itemKeyIsPressed = True
selectedItem = foundItem
selectedItem.Command.Invoke()
End If
End Select
Loop
End Sub
''' <summary>
''' Terminates the application.
''' </summary>
Private Sub EndConsole()
Environment.Exit(exitCode:=0)
End Sub
End Module
Traducción online a C# (sin testear):
using Microsoft.VisualBasic;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
static class Module1
{
/// <summary>
/// Defines a Console Menu Item.
/// </summary>
public sealed class ConsoleMenuItem
{
/// <summary>
/// Gets or sets the item text.
/// </summary>
/// <value>The item text.</value>
public string Text { get; set; }
/// <summary>
/// Gets or sets the <see cref="ConsoleKey"/> that activates this item.
/// </summary>
/// <value>The <see cref="ConsoleKey"/> that activates this item.</value>
public ConsoleKey Key { get; set; }
/// <summary>
/// Gets or sets the associated <see cref="Command"/> for this item.
/// </summary>
/// <value>The associated <see cref="Command"/> for this item.</value>
public Action Command { get; set; }
}
/// <summary>
/// A menu item that exists from console.
/// </summary>
private static readonly ConsoleMenuItem menuItemExit
= new ConsoleMenuItem
{ Text = "[X] Exit...",
Key = ConsoleKey.X,
Command = EndConsole
};
/// <summary>
/// The main menu items.
/// </summary>
private static readonly IEnumerable<ConsoleMenuItem> mainMenuItems = {
Text = "[1] Show first submenu",
Key = ConsoleKey.D1,
Command
= new Action
(() => { ShowMenu
(subMenuItems1
); }) },
Text = "[2] Show second submenu",
Key = ConsoleKey.D2,
Command
= new Action
(() => { ShowMenu
(subMenuItems2
); }) },
menuItemExit
};
/// <summary>
/// The first submenu items.
/// </summary>
private static readonly IEnumerable<ConsoleMenuItem> subMenuItems1 = {
Text = "[1] Print a 'Hello World!'",
Key = ConsoleKey.D1,
Command
= new Action
(() => { Console
.WriteLine("Hello World!"); }) },
Text = "[R] Return",
Key = ConsoleKey.R,
Command
= new Action
(() => { ShowMenu
(mainMenuItems
); }) },
menuItemExit
};
/// <summary>
/// The second submenu items.
/// </summary>
private static readonly IEnumerable<ConsoleMenuItem> subMenuItems2 = {
Text = "[1] Print the current date.",
Key = ConsoleKey.D1,
Command = () => { Console.WriteLine(System.DateTime.Today.ToLongDateString); }
},
Text = "[R] Return",
Key = ConsoleKey.R,
Command
= new Action
(() => { ShowMenu
(mainMenuItems
); }) },
menuItemExit
};
/// <summary>
/// Defines the entry point of the application.
/// </summary>
public static void Main()
{
ShowMenu(mainMenuItems);
System.Threading.Thread.Sleep(int.MaxValue);
}
/// <summary>
/// Shows a console menu.
/// </summary>
/// <param name="menuItems">The items that composes the menu.</param>
/// <param name="itemIndicator">A string that indicates the current menu item.</param>
private static void ShowMenu(IEnumerable<ConsoleMenuItem> menuItems, string itemIndicator = " -> ")
{
// The selected menu item.
ConsoleMenuItem selectedItem = menuItems(0);
// The index of the selected menu item.
int selectedIndex = 0;
// The object to read the user-input pressed key.
ConsoleKey currentKey = default(ConsoleKey);
// Flag that determines wether the user pressed a valid menu item key.
bool itemKeyIsPressed = false;
// Wait for a valid menu item key.
while (!(itemKeyIsPressed)) {
// Iterate the menu items to format the menu string.
System.Text.StringBuilder sb
= new System.Text.StringBuilder(); var _with1 = sb;
sb.AppendLine("===============================");
sb.AppendLine("=========== My Menu ===========");
sb.AppendLine("===============================");
sb.AppendLine();
foreach (ConsoleMenuItem menuItem in menuItems) {
if (object.ReferenceEquals(menuItem, selectedItem)) {
sb.AppendLine(string.Format("{0}{1}", itemIndicator, menuItem.Text));
} else {
sb
.AppendLine(menuItem
.Text.Insert(0,
new string(' ', itemIndicator
.Length))); }
}
sb.AppendLine();
sb.AppendLine("===============================");
// Clear the screen.
Console.Clear();
// Print the menu items.
Console.WriteLine(sb.ToString);
// Wait for user-input.
currentKey = Console.ReadKey(true).Key;
// Handle the pressed key.
switch (currentKey) {
case ConsoleKey.DownArrow:
// Decrease current item selection.
selectedIndex = menuItems.ToList.IndexOf(selectedItem);
if (selectedIndex < (menuItems.Count - 1)) {
selectedItem = menuItems(selectedIndex + 1);
} else {
selectedItem = menuItems.First;
}
break;
case ConsoleKey.UpArrow:
// Increase current item selection.
selectedIndex = menuItems.ToList.IndexOf(selectedItem);
if (selectedIndex != 0) {
selectedItem = menuItems(selectedIndex - 1);
} else {
selectedItem = menuItems.Last;
}
break;
case ConsoleKey.Enter:
// Run the selected item's command.
itemKeyIsPressed = true;
selectedItem.Command.Invoke();
break;
case ConsoleKey.Backspace:
// Return to previous menu (if any).
ConsoleMenuItem foundItem = (from item in menuItemswhere item.Key == ConsoleKey.R).FirstOrDefault;
if (foundItem != null) {
itemKeyIsPressed = true;
selectedItem = foundItem;
selectedItem.Command.Invoke();
}
break;
default:
ConsoleMenuItem foundItem = (from item in menuItemswhere item.Key == currentKey).FirstOrDefault;
if (foundItem != null) {
itemKeyIsPressed = true;
selectedItem = foundItem;
selectedItem.Command.Invoke();
}
break;
}
}
}
/// <summary>
/// Terminates the application.
/// </summary>
private static void EndConsole()
{
Environment.Exit(exitCode: 0);
}
}
//=======================================================
//Service provided by Telerik (www.telerik.com)
//Facebook: facebook.com/telerik
//=======================================================
Saludos