跳到主要內容

Windows Form Menu 動態建置

話說在 Web Form 中如果要動態產生 Menu 連結到網頁,其實實作還蠻容易的,只要把對應的連結處理好就可以,但在 Windows Form 中如果要動態產生 Menu 就比較複雜如果硬要寫的話,處理方法也有可是程式就會跟老太婆的裹腳布一樣又臭又長,因此在這邊與另一位同事Kyle討論後,有了以下的想法,來解決動態載入Menu的問題。
要動態建置Menu的方法,我們採用了Reflection中的Activator.CreateInstance,先處理了透過User Control的名稱來建立物件的方法,這樣的方法可以讓物件被動態的產生,程式碼如下:
/// <summary>
/// 動態載入usercontrol
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void ucMenu1_MenuEvent(object sender, EventArgs e)
{
 string ctlName = (sender as MenuDemo.Controls.ucMenu).CtlName;
 try
 {
  var ctl = (UserControl)Activator.CreateInstance(Type.GetType(string.Format("MenuDemo.Controls.uc{0}", ctlName)));
  this.pRight.Controls.Clear();
  this.pRight.Controls.Add(ctl);
 }
 catch (Exception ex) { }
}

這個方法是要在當 Menu 被點選的時候被觸發,才會建立 User Control,並且把這個User Control 塞到 Frame 的 User Control指定的容器中,接著來看Menu怎麼被產生出來。
Menu被產生出來的方式其實是根據我們所定義的XML檔(將來可修改為任何資料來源)來決定,XML格式如下:
<?xml version="1.0" standalone="yes"?>
<Menu>
  <MenuItem>
    <FoldNo>INV100</FoldNo>
    <PrgNo>INV110</PrgNo>
    <PrgName>公司基本資料建檔</PrgName>
  </MenuItem>
  <MenuItem>
    <FoldNo>INV100</FoldNo>
    <PrgNo>INV120</PrgNo>
    <PrgName>發票基本資料建檔</PrgName>
  </MenuItem>
  <MenuItem>
    <FoldNo>INV900</FoldNo>
    <PrgNo>INV910</PrgNo>
    <PrgName>選單設定</PrgName>
  </MenuItem>
  <MenuFold>
    <FoldNo>INV100</FoldNo>
    <FoldName>基本建檔</FoldName>
  </MenuFold>
  <MenuFold>
    <FoldNo>INV900</FoldNo>
    <FoldName>選單管理</FoldName>
  </MenuFold>
</Menu>

這個XML中定義了上層的選單如基本建檔、選單管理,第二層的選單如:基本建檔>公司基本建檔 或 選單管理>選單設定 所以讀取XML檔後就可以產生出第一層選單與第二層選單,為了處理這個XML所以也寫了一個 MenuHelpers 來處理XML其實就是將XML轉成DataSet然後取出需要的值再繫結成Menu。
/// <summary>
/// Menu繫結
/// </summary>
private void MenuBind() 
{
 this.menuStrip1.Renderer = new MyRenderer();
 List<MENUITEM> iList = MenuHelpers.GetMenuItem();
 List<MENUFOLD> fList = MenuHelpers.GetMenuFold();
 for (int j = 0; j < fList.Count; j++)
 {
  string FoldNo = fList[j].FOLDNO;
  string FoldName = fList[j].FOLDNAME;
  ToolStripMenuItem subItem = UtilityUI.AddContextMenu(FoldName,FoldNo, this.menuStrip1.Items,null);
  List<MENUITEM> pList = (from data in iList where data.FOLDNO == FoldNo select data).ToList<MENUITEM>();
  for (int i = 0; i < pList.Count; i++)
  {
   string pFoldNo = pList[i].FOLDNO;
   string PrgName = pList[i].PRGNAME;
   string PrgNo = pList[i].PRGNO;
   UtilityUI.AddContextMenu(PrgName, PrgNo,subItem.DropDownItems, new EventHandler(btn_ClickEvent));
  }
 }
 foreach (var item in this.menuStrip1.Items.Cast<ToolStripMenuItem>())
 {
  GetCheckMenuItemText(item);
 }
}

這裡面透過了一個UtilityUI去處理繫節Menu上,也透過實作MyRenderer來賦予MentStrip中Renderer的功能。也撰寫MenuDelegate讓Menu在被點選時能觸發UserControl的實體化的事件。
public delegate void MenuDelegate(object sender, EventArgs e);
public event MenuDelegate MenuEvent;//委派事件
void btn_ClickEvent(object sender, EventArgs e)
{
 this.CtlName = (sender as ToolStripMenuItem).Tag.ToString();
 if (MenuEvent != null) 
 {
  this.MenuEvent(this, null);
 }
}

最後面建立了一個User Contorl是個Frame用來定義選單與操作畫面的相對配置,所以當 Windows From 被啟動時
void MainForm_Load(object sender, EventArgs e)
{
 ucFrame ucFrame1 = new ucFrame();
 ucFrame1.Dock = DockStyle.Fill;
 this.Controls.Add(ucFrame1);
}

記得在Form被初始化的時候就呼叫這個事件Form_Load,這樣在視窗載入時就會呈現。
public MainForm()
{
 InitializeComponent();
 this.Load += new EventHandler(MainForm_Load);
}

後記:
其實這個部分還可以已有所改善,例如加入權限值,就可以決定那些清單需要載入那些不用。但是這純粹就是Menu對應的資料來源的處理。這樣的Menu設計模式可以讓程式要變更配置與清單內容時能夠更有彈性。
範例檔案:MenuDemo.zip

留言

這個網誌中的熱門文章

以管理者權限執行批次檔

最近有個專案需要執行批次檔,來進行某些設定或者城市的安裝,在XP上這個Script可以運行沒問題,可是一到Vista以後的Windows版本就無法運行了,最主要的原因是,UAC的管制的問題,幾經尋找,總算找到一個可行的解決辦法。

DataGridView欄位統一格式化

最近的工作內有一個需求,就是由於專案中有許多呈現資料的DataGridView,而其中的欄位需要呈現的包含金額、數字或者日期等格式,若要一個個的設定格式,如果有一天格式突然變更,可能就要苦工做到死,如何讓專案中的這些格式都統一就成了一個問題,經過了一番查找,發現可以透過DataGridView.CellFormatting Event來解決這個問題。

輕話要重聽,重話要輕聽 [IT邦幫忙鐵人賽 Day1]

在職場上總是會有被指導的時候,而這些被指導的過程中,就是你成長的時候,其實指導者願意告訴你,就是覺得你會有機會成長,所以才會提點,但提點的過程就會隨著指導者的EQ而有所不同,EQ高者會用比較婉轉的話語來告訴你,EQ低者會用比較強烈甚至傷其自尊的怒罵來指責你,此時此刻你所要學習的就是【輕話要重聽,重話要輕聽】。 由於明天(星期五)要繳交網頁的版面設計稿件給客戶,加上客戶直至星期二才交付相關素材,因此設計部門並沒有太多時間可以進行設計,這個案子大概是因為工作分配的關係就落在了一個半熟手的設計師手上,直至今天(星期四)早上,基於我是這個案子的PM,所以我找了負責這個專案的設計師開了一個小會討論,會中設計師也大概說明了設計理念與想法,而這些圖稿我也覺得應該還符合客戶期待,所以也就沒再多所著墨,會後我的主管突然提到想要看這些設計稿,當我把圖稿給主管看完後,只見主管的表情變得嚴肅,就像"突然李組長的眉頭一皺,發現結果並不單純",當下請了設計部的資深同仁來討論,頓時我也陷入了一陣糾結。結果當然是稿件還沒到客戶手上,主管當場就打槍了。不過這件事倒讓我發現了兩個現象: 現象1:就我的立場而言,要交給客戶的稿件是我同意的,所以當主管不滿意時,我應該要深刻的反省,包含稿件深度與質量的要求,但主管從頭到尾並沒有提到,也沒有多所責難,而是立即希望設計部進行調整,但當下的我卻選擇了【輕話要重聽】。也就是說,主管沒有責難,但我卻連主管要求的水準都達不到,是該自我反省,而非當作沒事一般。因此我將他列入工作紀錄中自省。 現象2:我們的主管EQ是個不錯的人,因此當他在討論稿件品質時,並沒有多所責難,僅是希望設計部門能趕緊補強調整,但是對於半熟手的設計師來說,等於否定了他的設計,因此設計師的失落感可想而知,這個時候其實他該選擇【重話要輕聽】,這些否定的話其實只是推動進步的一個挑戰,把話輕聽,別想太多,只要記得提點的重點,其他的否定就不該執著於上,因為如果只是執著別人的否定,那你就會忽略提點的重點。誰不是從被否定中成長的呢。 所以學習如何【輕話要重聽,重話要輕聽】這是職場生存的一個訣竅,前者是希望即便與你無關的事情,如果你重視他,將他學習下來,就會讓自己進步。後者是希望別著墨在否定的態度上,應該專心在如何讓否定成為肯定,了解為何否定,自然也會成為成長的動力。 第五屆IT邦幫忙鐵...