续多文档界面(MDI)系统框架-C#完整版(一)
http://www.cnblogs.com/raychn/archive/2010/07/23/1783520.html
前面讲了MDI程序设计概念和相关接口及类定义,并且实现了主窗体注册工具栏组件。通过上面详细介绍,我们
知道了主窗体与工具栏的互动关系,依赖关系和运作。那么,父窗体与子窗体之间互动是如何实现的呢?
我们先来分析子窗体的构成与未来无法预知的扩展。所谓扩展就是窗体特性化,个性化。A窗体有(a1,a2)功能,
B窗体不仅需要(a1,a2)还要(b1,b2)功能。假设(a1,a2)(b1,b2)是按钮集合的话?个性化特点就突出了!为下面
讲的窗体个性化埋下伏笔!子窗体是多样化的,初步分类有帮助窗体,数据编辑窗体,数据选择窗体,报表窗体,模式对话框,系统设置等等,这里无法枚举。不管有多少,统称子窗体。本着万物皆对象的原理,为何不抽象出一个IMdiChildForm的接口呢?
![ContractedBlock.gif](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![ExpandedBlockStart.gif](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
/// MDI子窗体的接口
/// </summary>
public interface IMdiChildForm
{
// 子窗体的工具栏组件
IToolbarRegister ToolbarRegister { get ; set ; }
// 注册MDI窗体内的ToolBar.param mdiForm ToolBar管理对象的实例
void RegisterToolBar(IToolbarRegister toolBarRegister);
void RegisterObserver(IObserver[] observers); // 注册子窗子观察者
IList Buttons { get ;} // 返回窗体的按钮
void InitButtons(); // 初始化窗体的按钮
bool IsClosing { get ; set ;} // 窗体是否关闭状态
}
IMdiChildForm规范了子窗体的操作。RegisterToolBar()方法向父窗体的Toolbar注册按钮。InitButtons()
方法创建子窗体的按钮,通过Buttons属性可以获取。RegisterObserver()方法注册子窗子的观察者。
有了这些方法和属性父窗体与子窗体互动雏形出来了。
上面讲到窗体个性化要通过什么方式实现呢?
首先对子窗体分类,可以分系统公共,数据操作,报表窗体及锁定窗体4种基础类型。突出个性化无非是改变MDI父窗体的Toolbar按钮样式,所以定义4种接口来支持窗体操作的类型。
分别是ISystemButtons(系统公共),IDataOperatable(数据操作),IPrintableForm(报表窗体)。
ISystemButtons接口
![ContractedBlock.gif](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![ExpandedBlockStart.gif](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
/// 系统按钮
/// </summary>
public interface ISystemButtons
{
IButtonInfo[] GetSystemButtons();
void DoClose(IButtonInfo button); // 关闭窗体
void DoHelp(IButtonInfo button); // 打开帮助
}
IDataOperatable接口
![ContractedBlock.gif](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![ExpandedBlockStart.gif](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
/// 支持数据操作的接口
/// </summary>
public interface IDataOperatable
{
IButtonInfo[] GetDataOperatableButtons();
void DoViewContent(IButtonInfo button); // 查看数据
void DoAdd(IButtonInfo button);
void DoEdit(IButtonInfo button);
void DoCancel(IButtonInfo button);
void DoSave(IButtonInfo button);
void DoDelete(IButtonInfo button);
}
IPrintableForm 支持打印功能的接口
![ContractedBlock.gif](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![ExpandedBlockStart.gif](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
/// 支持打印功能的接口
/// </summary>
public interface IPrintableForm
{
IButtonInfo[] GetPrintableButtons();
void DoPreview(IButtonInfo button);
void DoPrint(IButtonInfo button);
}
ILockableForm支持锁定/解除锁定功能的接口
![ContractedBlock.gif](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![ExpandedBlockStart.gif](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
/// 支持锁定/解除锁定功能的接口
/// </summary>
public interface ILockableForm
{
IButtonInfo[] GetLockableButtons();
void DoLock(IButtonInfo button);
void DoUnlock(IButtonInfo button);
}
子窗体接口定义完毕,接下来实现这些接口。
同时实现IMdiChildForm, ISystemButtons接口。
![ContractedBlock.gif](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![ExpandedBlockStart.gif](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
{
private IToolbarRegister _ToolbarRegister = null ; // 父窗体的Toolbar组件
private IList _buttons = new ArrayList(); // 初始化数组
private IList _observers = new ArrayList(); // 子窗体观察者列表
private IButtonInfo[] _SystemButtons = null ; // 子窗体的按钮数组
private bool _IsClosing = false ; // 窗体是否正在关闭状态
public frmBaseChild()
{
InitializeComponent();
}
#region IMdiChildForm Members
public IToolbarRegister ToolbarRegister
{
get { return _ToolbarRegister; }
set { _ToolbarRegister = value; }
}
public virtual void RegisterToolBar(IToolbarRegister toolBarRegister)
{
// this.Buttons是当前窗体的按钮数组。
toolBarRegister.RegisterButton( this .Buttons);
}
// 子窗体的按钮数组
public IList Buttons { get { return _buttons; } }
/// <summary>
/// 模板方法.初始化本窗体的按钮.
/// </summary>
public virtual void InitButtons()
{
IButtonInfo[] bi = this .GetSystemButtons();
if (bi != null )
foreach (IButtonInfo btn in bi) _buttons.Add(btn);
}
/// <summary>
/// 系统按钮列表。注:子窗体享用系统按钮,如帮助/关闭窗体常用功能。
/// </summary>
public virtual IButtonInfo[] GetSystemButtons()
{
if (_SystemButtons == null )
{
_SystemButtons = new IButtonInfo[ 2 ];
_SystemButtons[ 0 ] = this .ToolbarRegister.CreateButton( " btnHelp " ,
" 帮助 " ,
global ::VJSDN.Tech.MDI.Properties.Resources._24_Help, new Size( 57 ,
28 ), this .DoHelp);
_SystemButtons[ 1 ] = this .ToolbarRegister.CreateButton( " btnClose " ,
" 关闭 " ,
global ::VJSDN.Tech.MDI.Properties.Resources._24_Exit, new Size( 57 ,
28 ), this .DoClose);
}
return _SystemButtons;
}
public void DoHelp(IButtonInfo sender)
{
new frmAbout().ShowDialog();
}
public void DoClose(IButtonInfo sender)
{
this .Close();
}
#endregion
// 子窗体获取焦点时注册子窗体的按钮。
// 通过Form.Active我们可以看到主窗体的ToolBar动态变化。
private void frmBaseChild_Activated( object sender, EventArgs e)
{
this .RegisterToolBar( this .ToolbarRegister);
this .NotifyObserver(); // 通过其它观察者
}
private void frmBaseChild_FormClosed( object sender, FormClosedEventArgs e)
{
NotifyObserver(); // 当关闭窗体,要通知所有子窗体观察者
}
/// <summary>
/// 当前窗体是否正在关闭状态
/// </summary>
public bool IsClosing { get { return _IsClosing; }
set { _IsClosing = value; } }
/// <summary>
/// 注册子窗体观察者
/// </summary>
public void RegisterObserver(IObserver[] observers)
{
foreach (IObserver o in observers) _observers.Add(o);
}
// 通知观察者进行更新
private void NotifyObserver()
{
foreach (IObserver o in _observers) o.Notify();
}
private void frmBaseChild_FormClosing( object sender, FormClosingEventArgs e)
{
this .IsClosing = true ; // 正在关闭状态
}
}
实现IDataOperatable接口
![ContractedBlock.gif](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![ExpandedBlockStart.gif](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
/// 数据操作窗体演示.
/// </summary>
public partial class frmChildData : frmBaseChild, IDataOperatable
{
private IButtonInfo[] _DataButtons = null ;
#region IDataOperatable接口的方法
public IButtonInfo[] GetDataOperatableButtons()
{
// 如果已经创建按钮,不要重复创建。
if (_DataButtons == null )
{
_DataButtons = new IButtonInfo[ 6 ];
_DataButtons[ 0 ] = this .ToolbarRegister.CreateButton( " btnView " ,
" 查看 " ,
global ::VJSDN.Tech.MDI.Properties.Resources._24_ViewContent, new Size( 57 , 28 ), this .DoViewContent);
_DataButtons[ 1 ] = this .ToolbarRegister.CreateButton( " btnAdd " ,
" 新增 " ,
global ::VJSDN.Tech.MDI.Properties.Resources._24_Add, new Size( 57 , 28 ), this .DoAdd);
_DataButtons[ 2 ] = this .ToolbarRegister.CreateButton( " btnDelete " ,
" 删除 " ,
global ::VJSDN.Tech.MDI.Properties.Resources._24_Delete, new Size( 57 , 28 ), this .DoDelete);
_DataButtons[ 3 ] = this .ToolbarRegister.CreateButton( " btnEdit " ,
" 修改 " ,
global ::VJSDN.Tech.MDI.Properties.Resources._24_Edit, new Size( 57 , 28 ), this .DoEdit);
_DataButtons[ 4 ] = this .ToolbarRegister.CreateButton( " btnSave " ,
" 保存 " ,
global ::VJSDN.Tech.MDI.Properties.Resources._24_Save, new Size( 57 , 28 ), this .DoSave);
_DataButtons[ 5 ] = this .ToolbarRegister.CreateButton( " btnCancel " ,
" 取消 " ,
global ::VJSDN.Tech.MDI.Properties.Resources._24_Cancel, new Size( 57 , 28 ), this .DoCancel);
}
return _DataButtons;
}
// 查看数据
public void DoViewContent(IButtonInfo sender)
{
MessageBox.Show( " 正在从数据库获取数据,然后显示.... " );
}
public void DoAdd(IButtonInfo sender)
{
this .SetEditMode();
MessageBox.Show( " 正在新增数据.... " );
}
public void DoEdit(IButtonInfo sender)
{
this .SetEditMode();
MessageBox.Show( " 正在Edit数据.... " );
}
public void DoCancel(IButtonInfo sender)
{
this .SetViewMode();
MessageBox.Show( " Cancel完成. " );
}
public void DoSave(IButtonInfo sender)
{
this .SetViewMode();
MessageBox.Show( " Save完成. " );
}
public void DoDelete(IButtonInfo sender)
{
MessageBox.Show( " Delete完成 " );
}
#endregion
}
实现IPrintableForm接口
![ContractedBlock.gif](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![ExpandedBlockStart.gif](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
{
private IButtonInfo[] _PrintButtons = null ;
public IButtonInfo[] GetPrintableButtons()
{
if (_PrintButtons == null )
{
_PrintButtons = new IButtonInfo[ 2 ];
_PrintButtons[ 0 ] = this .ToolbarRegister.CreateButton( " btnPreview " , " 预览 " ,
global ::VJSDN.Tech.MDI.Properties.Resources._24_PrintPreview,
new Size( 57 , 28 ), this .DoPreview);
_PrintButtons[ 1 ] = this .ToolbarRegister.CreateButton( " btnDelete " ,
" 打印 " ,
global ::VJSDN.Tech.MDI.Properties.Resources._24_Print, new Size( 57 ,
28 ), this .DoPrint);
}
return _PrintButtons;
}
public void DoPreview(IButtonInfo sender)
{
MessageBox.Show( " 正在打开打印预览窗体... " );
}
public void DoPrint(IButtonInfo sender)
{
MessageBox.Show( " 正在打印... " );
}
}
实现ILockableForm接口
![ContractedBlock.gif](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![ExpandedBlockStart.gif](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
{
private IButtonInfo[] _DataButtons = null ;
public IButtonInfo[] GetLockableButtons()
{
// 如果已经创建按钮,不要重复创建。
if (_DataButtons == null )
{
_DataButtons = new IButtonInfo[ 2 ];
_DataButtons[ 0 ] = this .ToolbarRegister.CreateButton( " btnLock " ,
" 锁定 " ,
global ::VJSDN.Tech.MDI.Properties.Resources._24_Lock, new Size( 57 , 28 ), this .DoLock);
_DataButtons[ 1 ] = this .ToolbarRegister.CreateButton( " btnUnlock " ,
" 反锁定 " ,
global ::VJSDN.Tech.MDI.Properties.Resources._24_UndoBill,
new Size( 57 , 28 ), this .DoUnlock);
}
return _DataButtons;
}
public void DoLock(IButtonInfo button)
{
MessageBox.Show( " 已锁定单据! " );
}
public void DoUnlock(IButtonInfo button)
{
MessageBox.Show( " 已经解除锁定! " );
}
}
所有接口实现完毕,接下来是见证奇迹的时刻,请按f5.
![ContractedBlock.gif](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![ExpandedBlockStart.gif](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Reflection;
using VJSDN.Tech.MDI.Interfaces;
using System.Runtime.InteropServices;
namespace VJSDN.Tech.MDI.Library
{
/// <summary>
/// 系统工具类
/// </summary>
public class MdiTools
{
// 打开IE浏览器或打开Outlook
public static void OpenIE( string url)
{
// url= mailto:webadmin@vjsdn.com 打开Outlook
System.Diagnostics.Process.Start(url);
}
/// <summary>
/// 打开子窗体.
/// </summary>
/// <param name="mdi"> MDI主窗体 </param>
/// <param name="childFormClass"> 子窗体的名称空间 </param>
public static void OpenChildForm(IMdiForm mdi, Type formType)
{
Form child = ActiveChildForm(mdi as Form, formType.ToString());
if (child != null ) return ;
Form form = (Form)formType.Assembly.CreateInstance(formType.FullName);
if (form != null && form is Form)
{
child = form as Form;
if (form is IMdiChildForm)
{
(child as IMdiChildForm).ToolbarRegister = mdi.MdiToolbar;
(child as IMdiChildForm).RegisterObserver(mdi.MdiObservers);
child.MdiParent = (Form)mdi;
child.Show();
}
else
{
child.Show();
}
}
else
throw new Exception( " 未知窗体类型! " );
}
// 如果是已经打开的窗体,激活即可.
public static Form ActiveChildForm(Form mdi, string formTypeName)
{
for ( int x = 0 ; x < mdi.MdiChildren.Length; x ++ )
{
string ss = mdi.MdiChildren[x].GetType().ToString().ToUpper();
if (ss == formTypeName.ToUpper())
{
mdi.MdiChildren[x].Activate();
return mdi.MdiChildren[x];
}
}
return null ;
}
}
}
/// 观察者接口
/// </summary>
public interface IObserver
{
void Notify();
}
实现了3个观察者:
![ContractedBlock.gif](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![ExpandedBlockStart.gif](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
/// 观察用户是否关闭所有子窗体,如果用户关闭所有子窗体,显示MDI主窗体上的按钮
/// </summary>
public class ObserverCloseAllChild : IObserver
{
private Form _mdi = null ;
public ObserverCloseAllChild(Form mdi)
{
_mdi = mdi;
}
// 如果用户关闭所有子窗体,显示MDI主窗体上的按钮
public void Notify()
{
if (_mdi.MdiChildren.Length == 0 )
{
(_mdi as IMdiForm).RegisterMdiButtons();
}
else if (_mdi.MdiChildren.Length == 1 )
{
if (_mdi.MdiChildren[ 0 ] is IMdiChildForm)
{
if ((_mdi.MdiChildren[ 0 ] as IMdiChildForm).IsClosing)
(_mdi as IMdiForm).RegisterMdiButtons();
}
}
}
}
/// <summary>
/// 观察当前子窗体,在MDI主窗体内显示子窗体的标题
/// </summary>
public class ObserverFormState : IObserver
{
ToolStripStatusLabel _label = null ;
private Form _mdi = null ;
public ObserverFormState(Form mdi, ToolStripStatusLabel label)
{
_mdi = mdi;
_label = label;
}
public void Notify()
{
Form child = _mdi.ActiveMdiChild;
if (child != null )
{
if (child is IMdiChildForm)
{
if ((child as IMdiChildForm).IsClosing)
_label.Text = _mdi.Text;
else
_label.Text = child.Text;
}
else
_label.Text = child.Text;
}
else
_label.Text = " 没有打开子窗体. " ;
}
}
/// <summary>
/// 观察打个的窗体个数.
/// </summary>
public class ObserverOpenForms : IObserver
{
ToolStripStatusLabel _label = null ;
private Form _mdi = null ;
public ObserverOpenForms(Form mdi, ToolStripStatusLabel label)
{
_mdi = mdi;
_label = label;
}
public void Notify()
{
// 计算打开的子窗体个数,因Application.OpenForms.Count是所有打开的窗体数量,要减掉MDI主窗体.
int count = Application.OpenForms.Count - 1 ;
if (count < 0 ) count = 1 ;
_label.Text = string .Format( " 共打开{0}个窗体 " , count);
}
}
未完,后续(UML建模)....
==============================
多文档界面(MDI)系统框架已完成。链接地址:
系统介绍及接口设计
多文档界面(MDI)系统框架-C#完整版(一)
父窗体与子窗体之间互动关系及Toolbar实现
多文档界面(MDI)系统框架-C#完整版(二)
系统框架UML图
多文档界面(MDI)系统框架-C#完整版(三)(UML图)