最近写了一个程序,客户需要用Enter切换输入焦点,像TAB键那样(Windows Form, .net)。据说国内的很多应用软件都是这样,已经成为一种事实上的标准了。
既然是一种事实上的标准了,我想应该就有至少一种标准的实现吧。立刻请教一位在国内的软件公司作开发的朋友,他们公司的解决方案是:继承所有需要转换的控件,如TextBox, ComboBox, 重载OnKeyDown方法,如果输入Enter, 向应用程序发送TAB键盘事件。
向应用程序发送TAB键盘事件非常好,然而,继承所有的控件,实在不敢恭维,代码分散在各处且不说,如果碰到一个第三方控件,不能继承怎么办?
既然实现一个功能,而且实现的代码一样,首先应该考虑,能否在一个地方实现,不是在所有的控件中做同样的事。既然是截获控件的事件,首先想到的当然是Control.WndProc,因为它是所有控件的基类,然而,我们不能去修改Control。这时,想到MessageFilter是理所当然的了。
.net framework允许应用程序在消息派发到Control和Form之前截获到他。你只需要实现IMessageFilter,并通过Application.AddMessageFilter把它加到Application中。我们就可以为这个应用实现一个MessageFilter,如果收到WM_KEYDOWN事件,并且Key是Enter,其它的修饰键没有被按下的情况下,向应用程序发送TAB键盘事件,同时返回true,不往下派发Enter键,实现代码如下:
public class MessageFilter
: IMessageFilter
{
private
readonly static
IList StopControlTypes =
new Type[] {typeof(TextBox), typeof(ComboBox)};
private
const int
WM_KEYDOWN = 0x100;
{
}
{
if (m.Msg == WM_KEYDOWN &&
Control.ModifierKeys == Keys.None && m.WParam.ToInt32() == (int)Keys.Enter)
{
Control ctr
= Control.FromHandle(m.HWnd);
if (ctr == null)
{
ctr
= Control.FromChildHandle(m.HWnd);
}
if (ctr != null
&& StopControlTypes.IndexOf(ctr.GetType()) >= 0)
{
SendKeys.Send("{Tab}");
return true;
}
}
}
}
代码很简单。细细一想,你会发现,前一种方法是一种方法是一个纯OO的解决方案,而后一种,是一个AOP的解决方案,用Enter键实现切换焦点是程序的一个方面。 在程序中适当应用一些AOP的思想,虽然整体看来不是那么OO,却非常受用。

浙公网安备 33010602011771号