2010-09-27 2 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 с предложением 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, то somethin g нравится это.

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 ~ Clever – jcolebrand

+0

Я думаю, что это немного слишком продвинутым, очевидно ОП узнает о WinForms ... это кажется немного слишком ... – t0mm13b

+0

я не могу понять код mr.Preet Сангхи. :( – yonan2236

2

Может быть проще использовать «Tag» свойство класса и использования MenuItem, что вместо этого, и динамически наращивать пункты меню, добавив его в MenuStrip, и используя уникальный обработчик события нажатия для всех пункты меню, то это дело выяснить, какой тег был использован, для примера можно установить тег в форме, как этот

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

Вот что я думал, добавляя обработчики onclick динамически. Я думаю, вы могли бы даже переопределить EventHandler, чтобы передать третье значение с помощью этого метода, чтобы вы могли передать тип формы из кода. ... также, +1 для его создания, чтобы элемент меню мог быть добавлен в codebehind (возможно, он загружается из файла XML для полной настройки?): – jcolebrand

+0

Как я могу это использовать? – yonan2236

+0

вы бы повторили блок 'menuItem = new ... ... frmMDI.MenuStirp.Add (menuItem);' для каждого элемента, который вы хотели бы добавить в свою форму на загрузку (но у вас может быть ситуация, когда вам нужно ограничить часто этот блок работает ... просто соображение) – jcolebrand

0

хаком образом, чтобы сократить этот код (я не думаю, что это то, что вы имеете в виду tho: p)

Также обратите внимание: «IsXYZ (val)» подразумевает ответ bool ... подумайте об этом.Попробуйте «GetOpenForm (тип FormType)»

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

Обратите внимание, что это помогает определить «сократить код» ... вы только означает, deduping нажатия клавиш, необходимых для создания нового кода для новых случаев?

Также обратите внимание, что объединение ответов Preet и Tommie дает вам возможность взглянуть на sender и получить тип, вызывающий ваш метод, позволяющий настраивать там логику. Фанковая логика проверки для каждой формы по типу - это то, что вызывает чрезмерный сверток кода. Если бы был другой способ идентифицировать открытые окна, это могло бы сработать в вашу пользу.

2

Я думал о факторизации общей функциональности в универсальном методе. Он использует generics и 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) ~~ Кроме того, не мешает идти вперед и продолжать пропускать отправителя объекта EventArgs e' altho, который будет раздуваться, если он не понадобится. Больше примечания к @yonan – jcolebrand

+0

этот код работает для меня. и это вполне понятно ... спасибо sir Adrift – yonan2236

+0

@ yonan2236: вы очень приветствуетесь :) –

Смежные вопросы