打开Excel,我们发现Excel的每个Sheet里面并没有任何的功能操作按钮或菜单,但是我们仍然能对每个sheet进行各种操作,这些操作都可以 由上面的功能菜单来实现。对于MDI形式的界面,从某种程度上来看,就很类似一个Excel Application,那能不能实现像Excel Application那样的功能操作呢?
要实现那样的功能操作,有几个问题需要解决:
(1)MDI父界面能调用到MDI子界面的功能
(2)MDI子界面对通过一个功能,能不同实现
(3)MDI子窗口可以实现对父窗口的控件控制(扩展功能)
界面实现的形式如下:
上面是一般菜单,下面是通用功能按钮。每个按钮都可以实现子窗口的功能,通俗的说就是“不用你来调用我,只需我来调用你”(比较类似于观察者模式)。当然实现这中设计,每个子界面的功能要有很大的相似性才比较好,否则最好不要这样设计。
我们知道,在.net的方法调用中,如果是非静态的方法,需要先实例化类的对象,然后才能调用类的方法,如果是静态方法,也是需要知道具体的类才能调用其 方法。如果在MDI父窗口的功能要调用MDI子窗口的功能,是否需要实例化每个MDI子窗口的对象才能调用其方法呢?在.net的继承中,子类可以强制转 换成父类,如果每个子窗口都继承与某个父窗口,这样MDI父窗口调用MDI子窗口的功能的时候,只要实例化父窗口然后调用其方法就行了。通过虚函数和重写可以实现子类的多样化。
首先我们来定义一个父窗口,用于继承,比如命名为frmBase,然后定义其功能函数:
public partial class frmBase: Form
{
public virtual void PicPrintView()
{
MessageBox.Show("打印");
}
public virtual void UpdateStatus(int iStatus)
{
}
public virtual void PicSave()
{
}
}
定义个子窗口,都继承自frmBase,实现对应的功能函数:
public partial class frmCustomer: frmBase
{
public override void UpdateStatus(int iStatus)
{
MessageBox.Show(iStatus.ToString());
}
public override void PicSave()
{
MessageBox.Show("保存");
}
}
最后要实现的就是在MDI父窗口调用对应的功能。要调用MDI子窗口的功能能,我们首先要知道的是调用的是那个窗口的,对应MDI的形式,可以通过this.ActiveMdiChild获取当前活动的窗口,所以在MDI父窗口的事件上:
private void picPrint_Click(object sender, EventArgs e)
{
if (this.ActiveMdiChild != null)
{
frmBase frm = (frmBase)this.ActiveMdiChild;
frm.PicPrint();
}
}
这样就实现了对frmCustomer中打印功能的实现。如果每个子窗体的功能都一样,我们只需要在继承的父窗口实现功能,子窗口不重写对应的方法就行了,扩展开来,如果子窗口没有这个功能,不重写对应的方法就可以了(PicPrintView)。
写到这里,基本的功能已经实现了。其实主要就是使用了虚函数和重写,还有一个MDI窗口特有的属性ActiveMdiChild。我这里是通过方法来实现的,当然也可以通过委托来实现,还可以通过委托+事件来实现。
对于第三个功能“MDI子窗口可以实现对父窗口的控件控制”,主要是在子窗口不实现功能的时候使用。可能在MDI父窗体有多个按钮实现子界面的功能,但是某个子界面只需要实现其中的几个功能,虽然通过不重写方法就不实现了其中的功能,但是在可视化程序设计下,没有实现功能的控件(按钮,菜单等)最好不显示或者不可操作。
在MDI父窗口中,将其控件装换成其属性:
public Button BtnSave
{
get { return this.btnSave; }
}
public Button BtnNew
{
get { return this.btnSave; }
}
在继承父窗口,实现控制MDI父窗口控件的方法:
frmMain frm = null;
private void frmBase_ParentChanged(object sender, EventArgs e)
{
if (this.MdiParent != null)
frm = (frmMain)this.MdiParent;
}
public void ShowButton(bool bSave, bool bNew)
{
frm.BtnNew.Visible = bNew;
frm.BtnSave.Visible = bSave;
}
在继承子窗口,实现具体控制,即调用父类中的方法:
private void frmCustomer_Load(object sender, EventArgs e)
{
ShowButton(true, false);
}