WinForm控件开发总结(十二)-----让控件处理导航键

简介:
 最近真的真的太忙了,以至于一个多月都没哟更新我的 blog 。昨天晚上,一个网上的朋友看了我的 ToolBox 的文章,问我一个问题,他说如何让 ToolBox 控件也能响应键盘操作,也就是用 Up down 按键来选择工具箱控件里的 Item ,他添加了键盘事件,但是不起作用。一开始做这个控件的时候也只是演示一下控件的制作过程,只用了很短的时间做了一个,只考虑了用鼠标选取,没有考虑键盘操作,我想要添加键盘操作无非重载 KeyDown 事件,针对 Up Down 做一些响应就可以了。可是添加了重载了 OnKeyDown 事件后,结果和那位朋友所说的一样,没有任何作用,我设了断点,调试了一下,发现 KeyDown 根本捕获不到 Up Down 按键的点击,是什么原因呢,是不是忘记设控件的风格以便让它能够获得焦点?于是,我使用了语句:
   
None.gif SetStyle(ControlStyles.Selectable,  true );
依然没有效果,当我们在控件上按下 Down 键的时候,另一个控件获得了焦点。这时 Up Down 按钮只是起到了导航的作用就像 Tab 键一样。
      接下来,我在测试工程的窗体上放置了一个ListBox控件做一个对比,其实ToolBoxListBox在界面表现上有相似之处,就是都有子Item,并且在ListBox上点击Down是起作用的,ListBox并没有失去焦点,这说明这时UpDown按键没有成为导航键。我想Windows一定是对默认的导航键UpDown,Left,Right有默认的处理,除非你希望你的控件希望自己处理这些键。用反汇编工具看了一下ListBoxControl控件的源代码,发现一个有趣的函数:
None.gif protected   override   bool  IsInputKey(Keys keyData)
ExpandedBlockStart.gif
{
InBlock.gif    
if ((keyData & Keys.Alt) == Keys.Alt)
ExpandedSubBlockStart.gif    
{
InBlock.gif        
return false;
ExpandedSubBlockEnd.gif    }

InBlock.gif    
switch ((keyData & Keys.KeyCode))
ExpandedSubBlockStart.gif    
{
InBlock.gif        
case Keys.Prior:
InBlock.gif        
case Keys.Next:
InBlock.gif        
case Keys.End:
InBlock.gif        
case Keys.Home:
InBlock.gif            
return true;
ExpandedSubBlockEnd.gif    }

InBlock.gif    
return base.IsInputKey(keyData);
ExpandedBlockEnd.gif}

None.gif

在这里面,ListBoxControl允许PriorNextEndHome成为有效的输入键,接着一路跟下去,看看WinForm控件的基类Control的这个函数是如何处理的:
None.gif [UIPermission(SecurityAction.InheritanceDemand, Window = UIPermissionWindow.AllWindows)]
None.gif
protected   virtual   bool  IsInputKey(Keys keyData)
ExpandedBlockStart.gif
{
InBlock.gif    
if ((keyData & Keys.Alt) != Keys.Alt)
ExpandedSubBlockStart.gif    
{
InBlock.gif        
int num = 4;
InBlock.gif        
switch ((keyData & Keys.KeyCode))
ExpandedSubBlockStart.gif        
{
InBlock.gif            
case Keys.Left:
InBlock.gif            
case Keys.Up:
InBlock.gif            
case Keys.Right:
InBlock.gif            
case Keys.Down:
InBlock.gif                num 
= 5;
InBlock.gif                
break;
InBlock.gif
InBlock.gif            
case Keys.Tab:
InBlock.gif                num 
= 6;
InBlock.gif                
break;
ExpandedSubBlockEnd.gif        }

InBlock.gif        
if (this.IsHandleCreated)
ExpandedSubBlockStart.gif        
{
InBlock.gif            
return ((((intthis.SendMessage(0x8700)) & num) != 0);
ExpandedSubBlockEnd.gif        }

ExpandedSubBlockEnd.gif    }

InBlock.gif    
return false;
ExpandedBlockEnd.gif}

None.gif

      注意这一行 return  ((((intthis.SendMessage(0x8700)) & num) != 0);0x87 是什么windows消息呢,打开WinUser.h文件,发现是WM_GETDLGCODE,MSDN中的描述是这样的:
      The WM_GETDLGCODE message is sent to the window procedure associated with a control. By default, the system handles all keyboard input to the control; the system interprets certain types of keyboard input as dialog box navigation keys. To override this default behavior, the control can respond to the WM_GETDLGCODE message to indicate the types of input it wants to process itself.
      也就是说windows用这个消息来判断哪些类型的输入交给控件本身来处理。然后,我注意到,对于方向导航键,函数都给于一个值5this.SendMessage(0x8700))的返回值进行与操作,那么this.SendMessage(0x8700))的返回值都可能是什么值呢,WinUser.h中是这样声明的:
   
ExpandedBlockStart.gif /*
InBlock.gif * Dialog Codes
ExpandedBlockEnd.gif 
*/

None.gif
#define  DLGC_WANTARROWS     0x0001      /* Control wants arrow keys         */
None.gif
#define  DLGC_WANTTAB        0x0002      /* Control wants tab keys           */
None.gif
#define  DLGC_WANTALLKEYS    0x0004      /* Control wants all keys           */
None.gif
#define  DLGC_WANTMESSAGE    0x0004      /* Pass message to control          */
None.gif
#define  DLGC_HASSETSEL      0x0008      /* Understands EM_SETSEL message    */
None.gif
#define  DLGC_DEFPUSHBUTTON  0x0010      /* Default pushbutton               */
None.gif
#define  DLGC_UNDEFPUSHBUTTON 0x0020     /* Non-default pushbutton           */
None.gif
#define  DLGC_RADIOBUTTON    0x0040      /* Radio button                     */
None.gif
#define  DLGC_WANTCHARS      0x0080      /* Want WM_CHAR messages            */
None.gif
#define  DLGC_STATIC         0x0100      /* Static item: don't include       */
None.gif
#define  DLGC_BUTTON         0x2000      /* Button item: can be checked      */
       5 最贴切的表达就是DLGC_WANTMESSAGE | DLGC_WANTARROWS,也就是将方向键发送给控件处理,对于6呢,也就是DLGC_WANTMESSAGE| DLGC_WANTTAB,将Tab键发送给控件处理。
   
     从这段代码里和控件实际的行为我们可以得出一个结论,那就是,控件本身是不处理方向键和Tab键的,因为他们有默认的行为,也就是支持焦点在窗体的控件之间转换。如果你想要处理这些导航键,那么结论很简单,就是重载IsInputKey方法,它是一个保护类型的虚方法。        
      在 ToolBox 控件的代码里重载 IsinputKey 方法:
None.gif          protected   override   bool  IsInputKey(Keys keyData)
ExpandedBlockStart.gif        
{
InBlock.gif            
if ((keyData & Keys.Alt) == Keys.Alt)
ExpandedSubBlockStart.gif            
{
InBlock.gif                
return false;
ExpandedSubBlockEnd.gif            }

InBlock.gif            
switch ((keyData & Keys.KeyCode))
ExpandedSubBlockStart.gif            
{
InBlock.gif                
case Keys.Up:
InBlock.gif                
case Keys.Down:                
InBlock.gif                    
return true;
ExpandedSubBlockEnd.gif            }

InBlock.gif            
return base.IsInputKey(keyData);
InBlock.gif
ExpandedBlockEnd.gif        }

None.gif       

         当用户点击的键是 Up Down 的时候,返回 true ,这时我们的 OnKeyDown 方法里就可以捕获到 Up Down 的点击事件了。





本文转自纶巾客博客园博客,原文链接:http://www.cnblogs.com/guanjinke/archive/2007/05/11/743464.html,如需转载请自行联系原作者
目录
相关文章
|
C# 索引 Windows
Winform控件优化之TabControl控件的使用和常用功能
TabControl是一个分页切换(tab)控件,不同的页框内可以呈现不同的内容,将主要介绍调整tab的左右侧显示、设置多行tab、禁用或删除tabpage、隐藏TabControl头部的选项卡等
3736 0
Winform控件优化之TabControl控件的使用和常用功能
|
C# 容器
Winform控件优化之TabControl控件的美化和功能扩展
在基本的TabControl控件使用和功能之上,可以尝试对其进行美化和功能扩展,比如动态删除或添加tab、绘制图标按钮及鼠标hover时的背景变化、Tab从右向左布局的优化处理等。最重要...
2064 0
Winform控件优化之TabControl控件的美化和功能扩展
|
C# Windows
wpf怎么使用WindowsFormsHost(即winform控件)
原文:wpf怎么使用WindowsFormsHost(即winform控件) 使用方法:   1、首先,我们需要向项目中的引用(reference)中添加两个动态库dll,一个是.
5041 0
|
7月前
|
Java C# 索引
C#之 十九 使用WinForm控件
C#之 十九 使用WinForm控件
112 0
|
机器学习/深度学习 数据可视化 程序员
WinForm控件属性大全
WinForm控件属性大全
400 0
|
Web App开发
艾伟:WinForm控件开发总结(三)------认识WinForm控件常用的Attribute
在前面的文章里我们制作了一个非常简单的控件。现在我们回过头来看看这些代码透露出什么信息。   这个类是直接从Control类派生出来的,自定义控件都是直接从Control类派生出来的。这个类定义了一个属性TextAlignment,用来控制文本在控件中显示的位置:           ...
977 0
|
C# Windows 安全
WinForm控件与WPF控件的交互
原文:WinForm控件与WPF控件的交互 这个问题其实也可以理解为:怎样在WPF/XAML中使用Winform中的控件(如PictureBox)?首先看看XAML代码:(注意下面加粗的部分)              ...
1048 0
|
前端开发 C#
WPF 窗体显示最前端
原文:WPF 窗体显示最前端 版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/jjx0224/article/details/8782845 ...
1121 0
|
C#
在Winform窗体中使用WPF控件(附源码)
原文:在Winform窗体中使用WPF控件(附源码) 今天是礼拜6,下雨,没有外出,闲暇就写一篇博文讲下如何在Winform中使用WPF控件。原有是我在百度上搜索相关信息无果,遂干脆动手自己实现。 WPF控件的漂亮是Winform无法匹及的,本文主旨是在Winform工程中如何使用WPF控件。
1775 0
|
存储 开发框架 .NET

热门文章

最新文章