1. 程式人生 > >C# 多窗體之間方法呼叫

C# 多窗體之間方法呼叫

看似一個簡單的功能需求,其實很多初學者處理不好的,很多朋友會這麼寫:

//父窗體是是frmParent,子窗體是frmChildA
//在父窗體中開啟子窗體 
frmChildA child = new frmChildA();
child.MdiParent = this;
child.Show();


//子窗體調父窗體方法:
//錯誤的呼叫!!!!!!!!
(this.MdiParent as frmParent).ParentFoo();

知道錯在那裡嗎?錯在強依賴!如果父窗體與子窗體在同一個模組內看似沒有錯,因為這種反向引用在同一個模組內是可行的,但程式不能這麼寫,你把它寫死了!固化了!假設我們的專案不斷在擴充套件,需要將父窗體與子窗體分開在不同的模組,這段程式碼就完了!因為父窗體模組必須引用子窗體模組,而子窗體需要用到frmParent的類,又要引用父窗體的模組!這時構成了雙向引用,編譯不能通過,所以講程式寫死了!


有什麼辦法解除這種依賴關係呢?辦法是有的,就是使用介面解除依賴關係!


我們把程式改下:
/// <summary> 
/// 主窗體介面 
/// </summary> 
public interface IMdiParent
{
   void ParentFoo();
}

/// <summary> 
/// 子窗體介面 
/// </summary> 
public interface IMyChildForm
{
   void Foo();
}


主窗體的程式碼:
/// <summary> 
/// 主窗體,實現IMdiParent介面 
/// </summary> 
public partial class frmParent : Form, IMdiParent
{
   public frmParent()
   {
      InitializeComponent();
   }
   
   private void form1ToolStripMenuItem_Click(object sender, EventArgs e)
   {
      //開啟子窗體 
      frmChildA child = new frmChildA();
      child.MdiParent = this;
      child.Show();
   }
   
   private void menuCallFoo_Click(object sender, EventArgs e)
   {
      //呼叫子窗體的Foo()方法 
      Form activedChild = this.ActiveMdiChild;
      if ((activedChild != null) && (activedChild is IMyChildForm))
         (activedChild as IMyChildForm).Foo();
   }
   
   #region IMdiParent 成員
   
   public void ParentFoo()
   {
      MessageBox.Show("呼叫" this.GetType().FullName ".ParentFoo()方法!");
   }
   
   #endregion
}

子窗體的程式碼:
/// <summary> 
/// 子窗體,實現IMyChildForm介面 
/// </summary> 
public partial class frmChildA : Form, IMyChildForm
{
   public frmChildA()
   {
      InitializeComponent();
   }
   
   #region IMyChildForm 成員
   
   public void Foo()
   {
      MessageBox.Show("呼叫" this.GetType().FullName ".Foo()方法!");
   }
   
   #endregion
   
   private void btnParentFoo_Click(object sender, EventArgs e)
   {
      //呼叫父窗體的ParentFoo()方法 
      if ((this.MdiParent != null) && (this.MdiParent is IMdiParent))
      (this.MdiParent as IMdiParent).ParentFoo();
   }
   
   private void btnErrCall_Click(object sender, EventArgs e)
   {
      //錯誤的呼叫 
      (this.MdiParent as frmParent).ParentFoo();
   }



實現思路:
frmParent窗體所在的模組依賴frmChildA所在模組,而frmChildA只依賴IMdiParent介面,這正是《敏捷軟體開發》中所講的依賴倒置原則。最後,我們把IMdiParent介面部署在一個Common模組內,實際上frmParent與frmChildA只需要依賴Common模組。

Source Code for VS2008: