2016-10-25 22 views
1

我在控制檯中創建了一個帶有子菜單的菜單。一切正常,但我不知道是否不可能改進我的程序結構。簡化它並使其更通用。如何提高我在c中的菜單(控制檯)#

class MainClass 
{ 
    public static void Main(string[] args) 
    { 
     MainMenu(); 
    } 

    public static void MainMenu() 
    { 
     Console.WriteLine("Main Menu"); 
     Console.WriteLine("--------------------"); 
     Console.WriteLine("[1] Show activities"); 
     Console.WriteLine("[2] Show teachers"); 
     Console.WriteLine("[3] Show students"); 
     Console.WriteLine("[4] Exit the program"); 
     Console.WriteLine("--------------------\n"); 
     Console.WriteLine("Please select an option from 1-4\n"); 

     string choice = Console.ReadLine(); 
     int number; 
     bool result = Int32.TryParse(choice, out number); 
     if (result) 
     { 
      Console.Clear(); 
      SubMenu(number); 
     } 
     else 
     { 
      Console.WriteLine("Incorrect choice"); 
     } 
    } 

    public static void SubMenu(int mainMenuChoice) 
    { 
     switch (mainMenuChoice) 
     { 
      case 1: 
       Console.WriteLine("Activities"); 
       Console.WriteLine("[1] Show all activities"); 
       Console.WriteLine("[2] Find a activity by his code"); 
       Console.WriteLine("[3] Return Main Menu"); 
       Console.WriteLine("[4] Exit the program"); 
       Console.WriteLine("--------------------\n"); 
       Console.WriteLine("Please select an option from 1-4\n"); 
       break; 

      case 2: 
       Console.WriteLine("Teachers"); 
       Console.WriteLine("[1] Show all teachers"); 
       Console.WriteLine("[2] Find a teacher by his matricule"); 
       Console.WriteLine("[3] Return Main Menu"); 
       Console.WriteLine("[4] Exit the program"); 
       Console.WriteLine("--------------------\n"); 
       Console.WriteLine("Please select an option from 1-4\n"); 
       break; 

      case 3: 
       Console.WriteLine("Students"); 
       Console.WriteLine("[1] Show all students"); 
       Console.WriteLine("[2] Find a student by his matricule"); 
       Console.WriteLine("[3] Return Main Menu"); 
       Console.WriteLine("[4] Exit the program"); 
       Console.WriteLine("--------------------\n"); 
       Console.WriteLine("Please select an option from 1-4\n"); 
       break; 

      case 4: 
       Environment.Exit(0); 
       break; 
     } 
     string choice = Console.ReadLine(); 
     int number; 
     bool result = Int32.TryParse(choice, out number); 
     if (result) 
     { 
      Action(mainMenuChoice, number); 
     } 
     else 
     { 
      Console.WriteLine("Incorrect choice"); 
     } 
    } 
    public static void Action(int menu, int choice) 
    { 
     switch (menu) 
     { 
      case 1: 
       switch (choice) 
       { 
        case 1: 
         // Do Stuff 
         break; 

        case 2: 
         // Do Stuff 
         break; 

        case 3: 
         Console.Clear(); 
         MainMenu(); 
         break; 

        case 4: 
         Environment.Exit(0); 
         break; 
       } 
       break; 

      case 2: 
       switch (choice) 
       { 
        case 1: 
         // Do Stuff 
         break; 

        case 2: 
         // Do Stuff 
         break; 

        case 3: 
         Console.Clear(); 
         MainMenu(); 
         break; 

        case 4: 
         Environment.Exit(0); 
         break; 
       } 
       break; 

      case 3: 
       switch (choice) 
       { 
        case 1: 
         // Do Stuff 
         break; 

        case 2: 
         // Do Stuff 
         break; 

        case 3: 
         Console.Clear(); 
         MainMenu(); 
         break; 

        case 4: 
         Environment.Exit(0); 
         break; 
       } 
       break; 
     } 
    } 
} 

目前,如果我必須添加一個子菜單,我一定要添加一行到的MainMenu()函數,因爲這是你的選擇,我必須在子菜單()函數中添加的情況下,和儘可能多的Action()中的菜單。 只有一個子菜單沒關係,但如果我不得不添加一打,它很快就變得難以管理。 我應該可以通過一個或多個班,但我迷失在這個結構上。

回答

1

我做了一些事情來快速展示解決問題的一種方法。我評論了大部分代碼,但詢問是否有任何不清楚的地方。我的主要優點是你可以在一個地方聲明菜單作爲對象。在我的代碼中,我已經在Main方法中明確地做了這個,但是您可以輕鬆地編寫一個工廠方法來爲您生成菜單。

class Program 
{ 
    //represents a line/option in a menu 
    class MenuItem 
    { 
     // displayed in the menu 
     public string Text { get; set; } 

     //is there a sub menu 
     public bool HasSubMenu { get; set; } 

     // if there's a submenu, what's its id 
     public int? SubMenuId { get; set; } 

     //if there isn't a sub menu, what should we do 
     public Action Action { get; set; } 
    } 

    //represents one menu i.e. a collection of options 
    class Menu 
    { 
     public Menu() 
     { 
      MenuItems = new List<MenuItem>(); 
     } 

     public int MenuId { get; set; } 
     public List<MenuItem> MenuItems { get; set; } 
     public string Title { get; set; } 

     public void PrintToConsole() 
     { 
      foreach (MenuItem item in MenuItems) 
      { 
       Console.WriteLine(MenuItems.IndexOf(item) + " : " + item.Text); 
      } 
     } 
    } 

    //represents all the menus 
    class MenuCollection 
    { 
     public MenuCollection() 
     { 
      Menus = new List<Menu>(); 
     } 

     public List<Menu> Menus { get; set; } 

     public void ShowMenu(int id) 
     { 
      //get the menu we want to display and call its PrintToConsole method 
      var currentMenu = Menus.Where(m => m.MenuId == id).Single(); 
      currentMenu.PrintToConsole(); 

      //wait for user input 
      string choice = Console.ReadLine(); 
      int choiceIndex; 

      //once we have the users selection make sure its an integer and in range of our menu options 
      //if not then show an error message and re-display the menu 
      if (!int.TryParse(choice, out choiceIndex) || currentMenu.MenuItems.Count < choiceIndex || choiceIndex < 0) 
      { 
       Console.Clear(); 
       Console.WriteLine("Invalid selection - try again"); 
       ShowMenu(id); 
      } 
      else 
      { 
       // if the selection is good, then retrieve the corresponding menu item 
       var menuItemSelected = currentMenu.MenuItems[choiceIndex]; 

       // if there's a sub menu then display it 
       if (menuItemSelected.HasSubMenu) 
       { 
        Console.Clear(); 
        ShowMenu(menuItemSelected.SubMenuId.Value); 
       } 
       // otherwise perform whatever action we need 
       else 
       { 
        menuItemSelected.Action(); 
       } 
      } 
     } 
    } 

    static void Main(string[] args) 
    { 
     // build a collection of menus 
     // can have as deep a structure as you like 
     // give each menu a unique integer MenuId 
     // link to other menus by setting HasSubMenu to true, and the SubMenuId to the MenuId of the menu you wish to link to 
     // or, set HasSubMenu to false, and have an Action performed when the menuitem is selected 
     MenuCollection collection = new MenuCollection() 
     { 
      Menus = 
      { 
       new Menu() 
       { 
        MenuId = 1, 
        MenuItems = 
        { 
         new MenuItem() 
         { 
          Text = "Go to sub menu", 
          HasSubMenu = true, 
          SubMenuId = 2 
         }, 
         new MenuItem() 
         { 
          Text = "Print Action", 
          HasSubMenu = false, 
          Action =() => 
          { 
           Console.WriteLine("I printed from an action"); 
          } 
         } 
        } 
       }, 
       new Menu() 
       { 
        MenuId = 2, 
        MenuItems = 
        { 
         new MenuItem() 
         { 
          Text = "Sub menu option 1", 
          HasSubMenu = false, 
          Action =() => 
          { 
           Console.WriteLine("Printed from a sub menu"); 
          } 
         }, 
         new MenuItem() 
         { 
          Text = "Back to the top menu", 
          HasSubMenu = true, 
          SubMenuId = 1 
         } 
        } 
       } 
      } 
     }; 

     collection.ShowMenu(1); 
     Console.ReadLine(); 
    } 
} 
+0

謝謝你的回答非常清楚。我喜歡這種方法。 – bluebeel

0

我已經作出了很多的小CLI工具在最近,我只是充實了活動,但這裏的方法的一個例子,我一般喜歡採取很多分支菜單/邏輯:

class Program 
{ 

    static T GetChoice<T>(List<Tuple<string, T>> choices) 
    { 
     var i = 1; 
     choices.ForEach(x => Console.WriteLine($"[{i++}]: {x.Item1}")); 
     var choiceIndex = int.Parse(Console.ReadLine()); 
     return choices[choiceIndex - 1].Item2; 
    } 

    static void Main(string[] args) 
    { 
     Console.WriteLine("Main Menu: "); 
     var choices = new List<Tuple<string, Action>>() 
     { 
      new Tuple<string, Action>("Show Activities", ShowActivities), 
      new Tuple<string, Action>("Show Teachers", ShowTeachers), 
      new Tuple<string, Action>("Show Students", ShowStudents), 
      new Tuple<string, Action>("Exit", Exit), 
     }; 

     GetChoice(choices)(); 
    } 

    static void ShowActivities() 
    { 
     Console.WriteLine("Activities: "); 
     var choices = new List<Tuple<string, Action>>() 
     { 
      new Tuple<string, Action>("Show all activities", ShowAllActivities), 
      new Tuple<string, Action>("Find activity by code", FindActivityByCode), 
      new Tuple<string, Action>("Return to main menu",() => { Main(null); }), 
      new Tuple<string, Action>("Exit the program", Exit), 
     }; 

     GetChoice(choices)(); 
    } 

    static void ShowTeachers() 
    { 
     Console.WriteLine("Teachers: "); 
     var choices = new List<Tuple<string, Action>>(); 
    } 

    static void ShowStudents() 
    { 
     Console.WriteLine("Students: "); 
     var choices = new List<Tuple<string, Action>>(); 
    } 

    static void ShowAllActivities() 
    { 
     //Do stuff 
    } 

    static void FindActivityByCode() 
    { 
     //Do stuff 
    } 

    static void ReturnToMainMenu() 
    { 
     //Do stuff 
    } 

    static void Exit() 
    { 
     Environment.Exit(0); 
    } 
} 
+0

非常感謝您的回答。我只是不明白你的GetChoice方法的創建。這是一個通用的方法,但方法名稱之前的T是什麼? 通常它不是這樣的:static GetChoice ? – bluebeel

+0

這意味着它返回一個泛型類型,例如你可以在Tuple 列表上執行GetChoice,如果你想讓它們選擇一個名字或者某個東西,或者是一個Tuple列表上的GetChoice,如果你想要的話他們從活動ID列表中選擇一個整數等。 – ivanPfeff