如果你用 MFC 编写过多文档界面(MDI)Windows 程序,那么肯定知道:如果父窗口标题为“PCaption”,子窗口标题为“CCaption”,那么每当子窗口最大化并处于激活状态时,子窗口标题一般都会与父窗口标题合二为一,变成“PCaption-[CCaption]”。 这是一种 MDI 的默认行为。用 C# 编写多文档界面程序也不例外。很多用户都不喜欢这种缺省特性,往往想用定制的窗口标题取而代之。本文将示范如何在C#程序中定制和修改MDI应用的窗口标题。
如果用MFC来编程,只要改写框架窗口类的虚函数 CFrameWnd::OnUpdateFrameTitle 即可。那么在微软的 .NET 框架中如何用C#实现相同的功能呢?首先,我们必须理解 MDI 本身是如何通过 Windows 核心 API 来实现自己的行为特性的,其实这与MFC或者.NET的公共语言运行时(CLR)没有什么关系。在创建MDI应用时,框架及其子窗口有各自专门的窗口过程,DefFrameProc 和 DefMDIChildProc,一个处理各种 WM_MDIXXX 消息以及其它类似 WM_SIZE, WM_SYSCOMMAND 的消息,另一个实现 MDI 行为。
如果用纯 C 代码编写,那么必须自己负责用 DefFrameProc 和 DefMDIChildProc 创建窗口;在 MFC 中则使用 CMDIFrameWnd/CMDIChildWnd;.NET 框架平台里则设置 Form.IsMdiContainer 和 Form.MdiParent,不管用哪种方式,其核心都是 user kernel,尤其是 DefFrameProc,当 MDI 子窗口最大化时,它会联接父子窗口的标题文本来产生主窗口标题串。理解了这一点,下面我来示范如何改写MDI。这个例子的原始版本来自 MSDN 库中用C#写的 Scribble MDI(用 “scribble sample”搜索一下即可找到)。基本思路是首先在 Scribble 例子的 MainWindow 中改写 WM_GETTEXT 消息处理例程,必须添加两个数据成员:NormalText 和 MaximizedText,用它们来保存常态和最大化状态的标题 :
// in Scribble.cs, MainWindow class private String NormalText = "Scribble2"; private String MaximizedText = "Window is now maximized"; |
如果想让其它类存取这两个成员,那么可以通过属性机制代替数据成员,如:
private String normaltext; public String NormalText { get { return normaltext; } set { normaltext = value; } } |
因为在例子程序中 MainWindow 是唯一一个存取该字符串的类,所以没有必要使用属性机制。有了这两个新的数据成员,你要做的只是 改写 WM_GETTEXT 处理例程,返回子窗口最大化状态以及常态时的标题文本。那么如何改写 WM_GETTEXT 处理例程呢?