c#

位置:IT落伍者 >> c# >> 浏览文章

C#中如何处理父窗口及其子窗口标题


发布日期:2018年07月25日
 
C#中如何处理父窗口及其子窗口标题

如果你用 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/CMDIChildWndNET 框架平台里则设置 FormIsMdiContainer 和 FormMdiParent不管用哪种方式其核心都是 user kernel尤其是 DefFrameProc当 MDI 子窗口最大化时它会联接父子窗口的标题文本来产生主窗口标题串理解了这一点下面我来示范如何改写MDI这个例子的原始版本来自 MSDN 库中用C#写的 Scribble MDI(用 scribble sample搜索一下即可找到)基本思路是首先在 Scribble 例子的 MainWindow 中改写 WM_GETTEXT 消息处理例程必须添加两个数据成员NormalText 和 MaximizedText用它们来保存常态和最大化状态的标题

// in Scribblecs MainWindow class

private String NormalText = Scribble;

private String MaximizedText = Window is now maximized;

如果想让其它类存取这两个成员那么可以通过属性机制代替数据成员

private String normaltext;

public String NormalText

{

get { return normaltext; }

set { normaltext = value; }

}

因为在例子程序中 MainWindow 是唯一一个存取该字符串的类所以没有必要使用属性机制有了这两个新的数据成员你要做的只是 改写 WM_GETTEXT 处理例程返回子窗口最大化状态以及常态时的标题文本那么如何改写 WM_GETTEXT 处理例程呢?

WindowsForms 提供了一些 处理 WM_XXX 消息的虚拟函数如 OnResize/WM_SIZE等但是恰恰缺少与 WM_GETTEXT 相关东东(OnGetText/WM_GETTEXT)不要担心没有虚函数我们总是可以改写包罗万象的 WndProc 处理例程为此必须知道所处理的消息ID也就是 WM_GETTEXT 的消息 ID = xD有人会问你是怎么知道这个消息的 ID 是 xD 啊很简单一种方法是运行 SPY 获取另一种方法是直接查找Windows SDK 中的 winuserh 头文件一旦你能深入到 WndProc 这一层次编写代码那么你基本上能用 C 语言写程序了因为 Win API 和其它语言之间所有东东通过 WPARAMs 和 LPARAMs 参数传递的包括字符串在内对于 WM_GETTEXT 来说MessageLParam 是指向 char* 的指针MessageWParam 是该指针长度也就是说你必须完成将文本串拷贝到调用者的缓沖里好在这并不是太难下面是程序代码

public class MainWindow : SystemWindowsFormsForm

{

private String NormalText = Scribble;

private String MaximizedText = Window is now maximized;

// Handle WM_GETTEXT: Return maximized or

// normal text depending on

// state of active MDI child window

protected override void WndProc(ref Message m)

{

const int WM_GETTEXT = xD;

if (mMsg==WM_GETTEXT) {

Form active = thisActiveMdiChild;

String s = active!=null &&

activeWindowState==FormWindowStateMaximized ? MaximizedText :

NormalText;

char[] c = sToCharArray();

IntPtr buf = mLParam;

int len = cLength;

MarshalCopy(c buf MathMin((int)mWParam len));

mResult = (IntPtr)len;

return;

}

baseWndProc(ref m);

}

// rest of MainWindow unchanged from Scribble sample

}

经过上述的改动现在运行程序当MDI子窗口最大化时主窗口标题显示的文本是Window is now maximized如图一所示

图一 子窗口最大化时的主窗口标题

当两个窗口处于常态时其画面如图二所示

图二 子窗口在常态时两个窗口的标题               

上一篇:C#传值调用与引用调用

下一篇:使用C#构建带事件的签名ActiveX组件