定制VB.NET控件编程之拦截击键动作

翻译|其它|编辑:郝浩|2007-12-07 10:55:29.000|阅读 666 次

概述:

# 界面/图表报表/文档/IDE等千款热门软控件火热销售中 >>

一、 简介

  首先,本文假定你已经熟悉 VB
.net 和 Visual Studio.NET Windows 表单设计器。

  在开发定制 Windows 表单控件时,提供我们自己的下拉框类型编辑器来操作控件的属性常常是非常方便的。定制的类型编辑器不仅可以提供更为丰富的设计时刻体验,而且可能成为用户是否喜欢你的控件的决定因素。

  如果你决定创建你自己的下拉式类型编辑器,那么它应该遵循与内置的下拉框类型编辑器相类似的模式。让我们以 Anchor 属性为例。一种典型的操作该属性的设计时刻用户交互描述如下:

  · 用户选择属性格子中的 Anchor 属性并且点击属性格右边的下拉按钮。

  · 一种良好的图形控件是下拉框,它能够允许用户使用鼠标点击边缘或者使用箭头键来高亮某个边缘并使用空格键选择/取消选择它。

  · 用户可以通过按下 ENTER 键或点击下拉控件的外部来接收变化。为了取消这一变化,用户可以按下 ESC 键。

  下面,让我们来讨论具体的实现技术。

二、 实现

  首先,让我们构建一个 ResourceImageEditor 类型编辑器,它允许从当前文件系统中选择一个图像文件(就象内置的 ImageEditor 类一样)或者从一个程序集的 manifest 文件中选择一个图像资源。而且,在用户体验方面,该 ResourceImageEditor 的行为应该类似于系统内置的类型编辑器。下面是对我们要求的概述:

  1. 当用户从属性格子中选择一个属性时,该格子就会显示出来—以一个下拉框 UI 形式显示可以编辑的属性。

  2. 当点击下拉按钮时,当前程序集中的所有图像资源将显示出来。

  3. 当用户选择一个图像资源项,相应的图像即可以从程序集中进行加载。

  4. 允许选择一个图像文件,并且在下拉列表框中的最后一项将标记为“Browse...”。当用户点按“Browse...”项,将显示经典的打开文件对话框,用户能够从中选择一个图像文件。

  5. 通过单击鼠标或使用箭头键高亮某项并按回车键实际选择它从而允许用户从该下拉列表框中选择一项。这个下拉选择可以通过按下 ESC 键取消。

  ResourceImageEditor 是一个类型编辑器,因此它直接或间接地派生自System.Drawing.Design.UITypeEditor 类。我决定从内置的System.Drawing.Design.ImageEditor 类进行派生是因为它已经实现了图像文件选择功能。也就是说,ImageEditor.EditValue 实现将显示一个文件打开对话框以允许用户从文件系统中选择一个图像文件。然后,从我的派生类中调用这一功能只需要简单地调用 MyBase.EditValue 即可。

  为了实现上面第一个要求(在属性格子中显示下拉箭头按钮),我必须重载 GetEditStyle 方法以从 UITypeEditorEditStyle 枚举中返回适当的常数:

Public Overloads Overrides Function GetEditStyle( _
ByVal context As ITypeDescriptorContext) As UITypeEditorEditStyle
 Return UITypeEditorEditStyle.DropDown
End Function


  为了显示图像资源列表,我必须列举一个给定程序集中的所有资源并且仅在列表中显示图像资源。为了简化,我决定使用一种简单的约定:当一个资源名以一个有效图像文件扩展名(.bmp,.jpg,.gif...)结束时,我们就认为这是一种图像资源,并且把它包括到该下拉列表框中。而且,我使用图像资源名的集合来填充这个下拉 ListBox 控件,后面详预以详述。

  开始时,被枚举以查询图像资源的程序集就是包含 ResourceImageEditor 类的程序集。然而,我们可以通过把 ResourceImageEditor.ResourceAssembly 属性设置为任何有效的 System.Reflection.Assembly 参考来改变它。

  当用户从列表框中选择一个图像资源名时,该图像应该即可从给定的程序集中的 manifest 文件中加载。这是在 LoadResourceImage 方法内实现的:

Private Function LoadResourceImage(ByVal resourceName As String) As Image
Debug.Assert(Not resourceName Is Nothing)
 Dim ImageStream As System.IO.Stream = Me.ResourceAssembly.GetManifestResourceStream(resourceName)
 Return System.Drawing.Bitmap.FromStream(ImageStream)
End Function


  下拉用户接口是通过在重载的 EditValue 方法内动态地创建和填充一个 ListBox 控件实现的。编辑器也处理由 ListBox 生成的 Click 和 KeyDown 事件,因为这是拦截 ENTER 和 ESC 键所必需的。下列伪码显示了在 EditValue 方法中的实现逻辑:

Public Overloads Overrides Function EditValue(...)
'存储上下文信息以用于下拉 ListBox 事件处理器。
'创建并使用可用的图像资源名填充该 ListBox。
'添加我们的特殊“Browse...”项。
'绑定 ListBox 事件。
'在一个下拉窗口中显示该 ListBox。
End Function

三、 几个关键问题与解案

  为了开发 ResourceImageEditor,我创建了一个重载 Image 属性的 MyPictureBox(派生自System.
Windows.Forms.PictureBox),以便把 ResourceImageEditor 指定为该 Image 属性的类型编辑器。
然后,我编译这个控件的代码。之后,就可以把该 MyPictureBox 控件放到一个表单上并且调用下拉框用户接口......

  鼠标接口工作得很好。然而,当我使用键盘选择一项然后按下回车键时,该下拉列表框消失,而且我的选定内容丢失了(也就是说,前一个选择图像并没有改变)。我很快发现,当按下回车键时,该 ListBox 并没有生成 KeyDown 事件。

  尽管 ESC 键也产生 KeyDown 事件,但这不是一个问题;因为该下拉列表框会被自动关闭,而且我不必处理当前选择项。

  很明显,在 ListBox 控件能够处理它们之前,这个属性格“屏蔽”了 ENTER 和 ESC 键。

  为了简化而且还要解决问题,我要使用 ProcessDialogKey 方法。在消息预处理期间(处理对话字符,例如 TAB、RETURN、ESCAPE 和箭头键)时,调用这个方法。这个方法是在 System.Windows.Forms.Control 类内声明的—它简单地把该调用代理给该控件的父级(如果有的话)。我已经子类化该 ListBox 控件,并且重载了 ProcessDialogKey 方法来拦截回车键,如下所示:

Protected Overrides Function ProcessDialogKey(ByVal keyData As Keys) As Boolean
 If keyData = System.Windows.Forms.Keys.Return Then
  RaiseEvent Ent
ERPressed(Me, EventArgs.Empty)
  Return True 'True意味着我们已经处理了相应的键
 Else
  Return MyBase.ProcessDialogKey(keyData)
 End If
End Function


  不是从 ProcessDialogKey 实现内部生成 KeyDown 事件,我决定使用一种更为直接的方式: EnterPressed 事件。为了,我修改了 ResourceImageEditor.EditValue 的实现以处理这一事件(而不是 KeyDown 事件),而且一切都非常顺利。

  你可以使用这一技术来拦截任何 Control 派生的类(你使用它来实现你的类型编辑器中的下拉 UI)中的 ENTER 键。


标签:

本站文章除注明转载外,均为本站原创或翻译。欢迎任何形式的转载,但请务必注明出处、不得修改原文相关链接,如果存在内容上的异议请邮件反馈至chenjj@evget.com

文章转载自:Yesky

为你推荐

  • 推荐视频
  • 推荐活动
  • 推荐产品
  • 推荐文章
  • 慧都慧问
扫码咨询


添加微信 立即咨询

电话咨询

客服热线
023-68661681

TOP