2010-09-27 112 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