多文档界面(MDI)系统框架-C#完整版(二)[vjsdn]

续多文档界面(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 ExpandedBlockStart.gif 代码
 
   
/// <summary>
/// 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 ExpandedBlockStart.gif 代码
 
   
/// <summary>
/// 系统按钮
/// </summary>
public interface ISystemButtons
{
IButtonInfo[] GetSystemButtons();

void DoClose(IButtonInfo button); // 关闭窗体
void DoHelp(IButtonInfo button); // 打开帮助
}

IDataOperatable接口

ContractedBlock.gif ExpandedBlockStart.gif 代码
 
   
/// <summary>
/// 支持数据操作的接口
/// </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 ExpandedBlockStart.gif 代码
 
   
/// <summary>
/// 支持打印功能的接口
/// </summary>
public interface IPrintableForm
{
IButtonInfo[] GetPrintableButtons();

void DoPreview(IButtonInfo button);
void DoPrint(IButtonInfo button);
}

ILockableForm支持锁定/解除锁定功能的接口

ContractedBlock.gif ExpandedBlockStart.gif 代码
 
   
/// <summary>
/// 支持锁定/解除锁定功能的接口
/// </summary>
public interface ILockableForm
{
IButtonInfo[] GetLockableButtons();

void DoLock(IButtonInfo button);
void DoUnlock(IButtonInfo button);
}

子窗体接口定义完毕,接下来实现这些接口。
同时实现IMdiChildForm, ISystemButtons接口。

ContractedBlock.gif ExpandedBlockStart.gif 代码
 
   
public partial class frmBaseChild : Form, IMdiChildForm, ISystemButtons
{
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 ExpandedBlockStart.gif 代码
 
   
/// <summary>
/// 数据操作窗体演示.
/// </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 ExpandedBlockStart.gif 代码
 
   
public partial class frmChildPrint : frmBaseChild, IPrintableForm
{
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 ExpandedBlockStart.gif 代码
 
   
public partial class frmChildLock : frmBaseChild, ILockableForm
{
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.
2010072310515442.png

 

 

ContractedBlock.gif ExpandedBlockStart.gif 代码
 
   
MdiTools 类

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>
/// 观察者接口
/// </summary>
public interface IObserver
{
void Notify();
}

 

 

实现了3个观察者:

ContractedBlock.gif ExpandedBlockStart.gif 代码
 
   
/// <summary>
/// 观察用户是否关闭所有子窗体,如果用户关闭所有子窗体,显示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图)

转载于:https://www.cnblogs.com/raychn/archive/2010/07/23/1783549.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
注意,这是未完成版本!!! 由于作者工作原因,暂时没有时间完成,但是基本功能已经实现,有个小问题如果你解决了欢迎发送给我,谢谢! 请用VS2010打开。内含四个DLL工程,及一个DLL 的测试工程。 其中一个问题是,打开子窗口之后子窗口内容没有显示,单击子窗口客户区之后其内容才显示,目前作者没有解决。 /************************************************************************/ /* MdiPlus框架说明 */ /************************************************************************/ /** 项目名称: MdiPlus框架 版本号: v1.0.1 第一作者: Jef 地址: 中国/江苏 日期: 20100616 电子邮箱: dungeonsnd@126.com 版权: 1.本框架完全开源。您可以免费使用本程序,但在用于商业用途前请获得第一作者的许可。 2.您使用本程序而导致任何伤害以及经济损失,由过错方依法承担所有责任, 一概与第一作者及合作单位无关。 3.如果您使用本程序则表示您已经同意此版本协议!否则请勿使用! 项目功能: MdiPlus框架是在Windows平台下把SDI程序行为与MDI程序行为结合在一起的编程手段。 框架最适合: a.以GDI方式输出为主的应用程序。 b.需要多种文档模板输出的MDI程序。 c.需要一个类似于SDI应用程序的固定(禁止改变大小)的View进行绘图。 框架充分进行模块化,把MDI的窗口创建类放在一个单独的DLL中(DllMdiWnd.dll),开发者应该继承 这个类来得到一个文档模板(这样继承者不必考虑创建细节,只负责绘图),并且每一个文档模板最好 放到一个DLL中(如ADoc.dll,BDoc.dll,CDoc.dll)。开发者建立主程序来调用ADoc.dll,BDoc.dll, CDoc.dll,每个文档模板(如ADoc.dll)可产生多个对应子窗口。 不过,DllMdiWnd.dll并没有提供view/doc支持,它的职责只是创建及销毁调用者的需要子窗口。 (如果子窗口是new创建出来的,ADoc.dll的基类CMdiPlus中自己会负责delete,开发者可以不调用 delete)。 当然,如果有必要你可以在DLL(A.dll,B.dll,C.dll)中实现view/doc支持。建议根据 需要开发独立的数据模型模块。 如果按照MVC模式的划分,DllMdiWnd.dll可以理解为C(控制器,创建与销毁窗口),继承类(如ADoc.dll, BDoc.dll,CDoc.dll)类似于V(视图,负责显示数据),这个框架没有提供M(模型,数据存储)。开发者 应该结合不同的文档模板来实现M。 版本历史: v1.0.1 20100616 第一版本 如何使用: 方法1. 进行项目开发时先建立DLL工程(建议选择 add mfc header win32 dll),然后把 DllMdiWnd.dll拷贝到新建项目中。根据应用需要的不同文档模板建立多个对应的Dll工程,这些Dll 都继承自DllMdiWnd.dll的导出类,假定为ADoc.dll,BDoc.dll,CDoc.dll,这些Dll隐式链接DllMdiWnd.dll。 接着建立支持doc/view类型的MDI MFC主程序工程,隐式链接ADoc.dll,BDoc.dll,CDoc.dll。 另外要特别注意的是,主程序要进行必要的修改,如CChildFrame中要修改窗口样式。建立的MDI 主程序运行过程中将完全类似于SDI程序。如,弹出子窗口时它的视图仍然保持最大化(普通的MDI应用 程序中任意一个子窗口从最大化还原时,其它窗口都将处于非最大化状态),并且它永远处于弹出的 子窗口下面,只能(且必须)建立一个CChildFrame。主程序的所有绘图工作都在这个 CChildFrame对应的view上进行。如果需要调用子窗口,只需要创建ADoc.dll(或BDoc.dll,CDoc.dll)导 出类的对象即可。子窗口的所有绘图工作都在ADoc.dll(或BDoc.dll,CDoc.dll)中实现,所以主程序与 ADoc.dll(或BDoc.dll,CDoc.dll)应该同时开发。 方法2. 开发者可以自己根据需要直接修改Demo版进行开发。 其它: 框架有点类似于多个文档模板的MDI应用程序,但是普通的MDI程序在新建一个文档前无法绘图,除非 子类化CMainFrame或截获CMDIClient的消息。这些方式不便进行模块化开发。MdiPlus框架主要优点是在 新建一个文档前就有一个View进行绘图,并且不同功能进行模块化,各模块放到Dll中(如果必要,你也 可以直接写成静态库链接到最终的执行程序里),适合一个项目多人同时进行开发。 **/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值