2010-09-27 114 views
3

我學習MDI窗體中的窗口形式,我用這個簡單的應用玩: alt text有沒有辦法縮短這段代碼? C#的WinForms

每個ToolStripMeniItem調用特定形式的單個實例,但你可以看到(請參閱我的代碼)我的代碼對於每個ToolStripMeniItem都是重複的,我怎麼縮短這個?

 public static Form IsFormAlreadyOpen(Type FormType) 
     { 
      foreach (Form OpenForm in Application.OpenForms) 
      { 
       if (OpenForm.GetType() == FormType) 
        return OpenForm; 
      } 
      return null; 
     } 

     private void form1ToolStripMenuItem_Click(object sender, EventArgs e) 
     { 
      Form1 f1 = null; 
      if (IsFormAlreadyOpen(typeof(Form1)) == null) 
      { 
       f1 = new Form1(); 
       f1.MdiParent = this; 
       f1.Show(); 
      } 
      else 
      { 
       Form selectedForm = IsFormAlreadyOpen(typeof(Form1)); 
       foreach (Form OpenForm in this.MdiChildren) 
       { 
        if (OpenForm == selectedForm) 
        { 
         if (selectedForm.WindowState == FormWindowState.Minimized) 
         { 
          selectedForm.WindowState = FormWindowState.Normal; 
         } 
         selectedForm.Select(); 
        } 
       } 
      } 
     } 

     private void form2ToolStripMenuItem_Click(object sender, EventArgs e) 
     { 
      Form2 f2 = null; 
      if (IsFormAlreadyOpen(typeof(Form2)) == null) 
      { 
       f2 = new Form2(); 
       f2.MdiParent = this; 
       f2.Show(); 
      } 
      else 
      { 
       Form selectedForm = IsFormAlreadyOpen(typeof(Form2)); 
       foreach (Form OpenForm in this.MdiChildren) 
       { 
        if (OpenForm == selectedForm) 
        { 
         if (selectedForm.WindowState == FormWindowState.Minimized) 
         { 
          selectedForm.WindowState = FormWindowState.Normal; 
         } 
         selectedForm.Select(); 
        } 
       } 
      } 
      // and so on... for the other ToolStripMeniItem 
     } 

回答

5

A generic function是將一組將被調用者

所以不是 int doubleIt(int a) { return a*2; } 定義的類型的工作,你可以說
T doubleIt<T>(T a){ return a*2; }

這意味着你可以一個函數定義一個可以這樣調用的函數:

int intResult = doubleIt(...pass in a int..); 
double doubleResult = doubleIt(...pass in a double..); 
float floatResult = doubleIt(...pass in a float..); 

因此,對於你的代碼中創建,把你正在創建爲T.

但是編譯器不知道T是一個形式的價值形態類型的方法,並且可以在新呼叫所以你必須禁止可以通過T的類型,用where子句說T必須是一個形式,並且必須是一個構造函數,你可以訪問

因此,你用一個通用函數替換核心功能,到您需要的f1類型。

所以不是Form f1 = null;您有在T f1 = null;

private void ClickEvent<T>(object sender, EventArgs e) where T: Form, new() { 
      T f1 = null; 
    . 
    . 
    . 
} 

傳遞一個泛型類型然後從真實事件調用此方法處理

private void form1ToolStripMenuItem_Click(object sender, EventArgs e)  { 
      ClickEvent<Form1>(sender, e) 
     } 

     private void form2ToolStripMenuItem_Click(object sender, EventArgs e) { 
      ClickEvent<Form1>(sender, e) 
     } 

所以,你最終的東西,如:

public static Form IsFormAlreadyOpen(Type FormType) 
{ 
    foreach (Form OpenForm in Application.OpenForms) 
    { 
     if (OpenForm.GetType() == FormType) 
      return OpenForm; 
    } 
    return null; 
} 

private void ClickEvent<T>(object sender, EventArgs e) where T: Form, new() 
    { 
    T f1 = null; 
    if (IsFormAlreadyOpen(typeof(T)) == null) 
    { 
     f1 = new T(); 
     f1.MdiParent = this; 
     f1.Show(); 
    } 
    else 
    { 
     Form selectedForm = IsFormAlreadyOpen(typeof(T)); 
     foreach (Form OpenForm in this.MdiChildren) 
     { 
      if (OpenForm == selectedForm) 
      { 
       if (selectedForm.WindowState == FormWindowState.Minimized) 
       { 
        selectedForm.WindowState = FormWindowState.Normal; 
       } 
       selectedForm.Select(); 
      } 
     } 
    } 
} 

    private void form1ToolStripMenuItem_Click(object sender, EventArgs e)  { 
     ClickEvent<Form1>(sender, e) 
    } 

private void form2ToolStripMenuItem_Click(object sender, EventArgs e) { 
    ClickEvent<Form1>(sender, e) 
} 

額外:如果你可以使用Linq,那麼事端像這樣。

using System.Linq; 

      public static Form IsFormAlreadyOpen(Type FormType)  {  
       return Application.OpenForms.Where(f => f.GetType() == FormType).FirstOrDefault(); 
      } 

      private void ClickEvent<T>(object sender, EventArgs e) where T: Form, new() 
      { 
       T selectedForm = IsFormAlreadyOpen(typeof(T); 
       if (selectedForm == null)    { 
        (new T() { MdiParent = this; }).Show() 
       } 
       else { 
        this.MdiChildren.Where(o => o == selectedForm).ForEach(
         openForm => { 
          selectedForm.WindowState = (selectedForm.WindowState == FormWindowState.Minimized) ? FormWindowState.Normal : selectedForm.WindowState; 
          openForm.Select(); 
         } 
        ); 
       } 
      } 
      private void form1ToolStripMenuItem_Click(object sender, EventArgs e)  { 
       ClickEvent<Form1>(sender, e) 
      } 

      private void form2ToolStripMenuItem_Click(object sender, EventArgs e) { 
       ClickEvent<Form2>(sender, e) 
      } 

還有其他的事情可以縮短這段代碼,但是泛型和linq的使用將是最有效的。

+0

@Preet〜聰明 – jcolebrand 2010-09-27 00:34:10

+0

我認爲這是一個有點太先進,顯然OP正在瞭解的WinForms ...這似乎有點矯枉過正... – t0mm13b 2010-09-27 00:34:29

+0

我無法理解mr.Preet僧團的代碼。 ( – yonan2236 2010-09-27 00:35:37

2

可能會更容易使用「標籤」屬性菜單項類和使用這些替代,並動態地構建起來的菜單項將它添加到MenuStrip中,並使用一個單一的Click事件處理程序所有菜單項,然後它找出的問題是使用哪種標籤,對於例如,你可以設置標籤這樣

menuItem = new MenuItem("Form 1"); 
menuItem.Tag = Form1; 
menuItem.Click += new EventHandler(frmMDI_FormHandler_Click); 
frmMDI.MenuStrip.Add(menuItem); 
+0

這就是我的想法,動態添加onclick處理程序。我想你甚至可以重寫EventHandler來使用這個方法傳遞第三個值,所以你可以從代碼中傳遞表單類型。 ...還有+1,可以在代碼隱藏中添加菜單項(可能從XML文件加載完全可定製?:p) – jcolebrand 2010-09-27 00:34:46

+0

我該如何使用它? – yonan2236 2010-09-27 00:42:06

+0

你會重複塊'menuItem = new ... ... frmMDI.MenuStirp.Add(menuItem);'你想要添加到你的表單中的每個項目onload(但你可能有一個情況,你需要限制通常這塊運行...只是一個考慮) – jcolebrand 2010-09-27 00:45:51

0

hackish的方式來縮短這個代碼的形式(我不認爲這是什麼你的意思是:p)

另請注意:「IsXYZ(val)」意味着布爾響應......考慮一下。嘗試「GetOpenForm(類型FormType)」

public static Form IsFormOpen(Type FormType) { 
    foreach (Form OpenForm in Application.OpenForms) 
    if (OpenForm.GetType() == FormType) 
     return OpenForm; 
    return null; 
} 

注意,它有助於界定「縮短代碼」 ......你只能意味着重複數據刪除,以產生新的情況下,新代碼所需的按鍵嗎?

此外,請注意,結合Preet和Tommie的答案,您可以查看sender並獲取調用方法的類型,從而允許您在其中自定義邏輯。按類型檢查每個表單的時髦邏輯是什麼導致代碼看起來過於複雜。如果有另一種方法來識別打開的窗戶,那可能對你有利。

2

我在考慮將通用功能分解爲通用方法。它確實使用泛型和Activator.CreateInstance,但除此之外,下面的代碼幾乎都是OP的代碼,只是重構而已。

private void form1ToolStripMenuItem_Click(object sender, EventArgs e) 
{ 
    OpenForm<Form2>(); 
} 

private void OpenForm<T>() where T : Form 
{ 
    T form = null; 

    if (IsFormAlreadyOpen(typeof(T)) == null) 
    { 
     form = Activator.CreateInstance<T>(); 
     form.MdiParent = this; 
     form.Show(); 
    } 
    else 
    { 
     Form selectedForm = IsFormAlreadyOpen(typeof(T)); 
     foreach (Form OpenForm in this.MdiChildren) 
     { 
      if (OpenForm == selectedForm) 
      { 
       if (selectedForm.WindowState == FormWindowState.Minimized) 
       { 
        selectedForm.WindowState = FormWindowState.Normal; 
       } 
       selectedForm.Select(); 
      } 
     } 
    } 
} 
+0

除了輸入錯誤? (eeek,ohnoes)~~另外,如果不需要的話,不要傷害繼續並繼續傳遞'object sender,EventArgs e',否則會膨脹。更多關於@yonan的說明 – jcolebrand 2010-09-27 00:51:06

+0

此代碼適用於我。這是可以理解的......謝謝先生Adrift – yonan2236 2010-09-27 00:56:01

+0

@ yonan2236:你非常歡迎:) – 2010-09-27 01:36:06