为 Windows 窗体控件添加上下文敏感功能






4.07/5 (3投票s)
2006 年 2 月 10 日
6分钟阅读

40960

420
用图形化的东西替换右键菜单。


引言
我目前正在开发一个应用程序的早期阶段,该应用程序允许用户使用预定义的图形元素库创建图表。这些图形元素的每个元素都有在其上下文为该元素实例时可用的功能。我决定这种上下文敏感功能应由与图形元素关联的附加控件提供,而不是通过右键菜单。本文介绍了我如何通过创建一个库来设计和开发解决此问题的方法,该库提供了一种将一个或多个视觉提示集附加到父控件的方法,然后通过处理父控件的某些鼠标事件来管理这些视觉提示的可见性。
目前,该库提供了创建 Cues 对象、将其注册到父 Control 并然后将任意数量的视觉提示集添加到该 Control 的能力。每个视觉提示集都基于指定的模型 Control,并且每个单独的视觉提示可以位于父 Control 周围的某个预定义点,或者位于绝对位置。视觉提示的可见性由 MouseEnter 和 MouseLeave 事件处理,其中显示和隐藏计时器相应地启动和停止。它还确保任何附加到可能在运行时更改位置的父 Control 的视觉提示将通过处理 LocationChanged 事件跟随该 Control。
示例应用
除了视觉提示库之外,源代码还包含一个名为 CueTest 的小型应用程序,该应用程序演示了一些视觉提示。
- CueTest 窗体包含多个控件,每个控件都附加了一些视觉提示。
- 拖放面板包含两个可拖动的控件,每个控件都带有一组角落提示,演示了重新定位。还有一个帮助 (?) 按钮。
- Button附加了一组视觉提示,并通过处理- Click事件来显示- Messagebox。
- TextBox附加了三组视觉提示,一组包含一个清除按钮,一组包含一个选择列表,每一组都与其父控件交互。最后一组包含一个帮助 (?) 按钮。
- PictureBox附加了三组视觉提示,第一组包含位于角落的提示,这些提示没有任何功能。第二组包含一个帮助 (?) 按钮,第三组包含两个图像导航按钮。
一些视觉提示基于本地 .NET 控件,一些是我创建的扩展版本。每个视觉提示集的可见性由其父控件的鼠标事件和它们的显示/隐藏计时器控制。
类描述
Cues(扩展 ArrayList)。Cues 类是视觉提示层次结构的顶级类,它维护一个 CueList 对象集合。它的构造函数接收父 Control 的引用,该引用用于注册 Cues 对象。Cues 类包含处理父 Control 的 MouseEnter、MouseLeave 和 LocationChanged 事件的代码。它包含多个重载方法,这些方法返回 CueList 对象,从而可以在各种预定义或绝对位置创建视觉提示。
CueList(扩展 ArrayList)。CueList 类维护一个 CueAdaptor 对象集合。它提供了一种引用附加到父 Control 的视觉提示集的方法。它包含公共方法 StartShow()、StopShow()、StartHide() 和 StopHide(),这些方法控制视觉提示可见性计时器。
CueAdaptor。CueAdaptor 类是适配器模式实现的一部分,它允许 Windows.Forms.Control 作为视觉提示参与,而无需扩展或实现任何特定接口。它的构造函数接收父 Control 和视觉提示控件的引用。CueAdaptor 类处理父 Control 和视觉提示之间的事件传递,反之亦然。
CuePosition。CuePosition 类维护描述视觉提示相对于其父 Control 位置的属性。如果其父控件的位置在运行时发生更改,此类还负责坐标计算和视觉提示重新定位。
视觉提示类图

创建一套视觉提示
将一套视觉提示添加到 Windows.Forms.Control 需要最多五个步骤。
第一步。创建 Cues 的实例并注册父 Control。Cues 扩展 System.Collections.ArrayList,用于存储附加到父控件 con 的任意数量的视觉提示集。
RestlessCues.Cues cues = new RestlessCues.Cues(con);
第二步。创建将用作附加到父控件的视觉提示的模型 Windows.Forms.Control 派生类的实例。
System.Windows.Forms.Button cue = new Button();
第三步。如果您需要在创建视觉提示时获取对视觉提示列表的句柄,那么您需要一个 CueList。如果您需要处理视觉提示控件引发的任何事件,您将需要它。
CueList buttonList;
第四步。创建一套视觉提示并将其附加到父控件。本示例将创建一个单一视觉提示,该提示基于“cue”类型,位于基于父控件 (con) 坐标的绝对位置。其他属性设置了视觉提示的宽度(45)和高度(20)、父控件与视觉提示之间的间隙(1),以及显示延迟(10)和隐藏延迟(1000)的两个计时器值。
buttonList = cues.AddCue(cue, new Point(con.Width - 50, 
             con.Height - 25), 45, 20, 1, 10, 1000);
每个视觉提示都基于指定的模型类型创建。
// Get Base Type of model Cue
Type type;
type = cueModel.GetType();
System.Windows.Forms.Control cue;
cue = (System.Windows.Forms.Control)Activator.CreateInstance(type);
该库包含许多 Add Cue 例程,用于在角落、北部、南部、东部和西部创建预定位置的视觉提示集,或单独创建 N、S、E、W。
cues.AddCornerCues(cue, 7, 4, 0, 10, 1000);
cues.AddCue(cue, CueDirection.N, 100, 20, 1, 10, 1000);
cues.AddSideCues(cue, 10, 10, 1, 10, 1000);
第五步。使用 CueList,迭代 CueAdaptors 集合以注册事件处理程序或更改视觉提示控件的属性。
foreach (CueAdaptor ca in buttonList)
{
    ca.ClickEvent += new CueClickEventHandler(TextBoxClearButton_Click);
    ca.CueControl.Text = "Help";
}
顺序图
以下顺序图说明了处理 MouseEnter 和 MouseLeave 事件所产生的逻辑流程。

该图突出了显示和隐藏计时器 Importance。这些计时器与 CueList 相关联,由父控件的 MouseEnter 和 MouseLeave 事件启动和停止。它们是必不可少的,原因有两个:首先,它们为开发人员提供了一种设置上下文敏感功能可用和消失之间延迟的方法;其次,它们克服了 MouseLeave 事件在父控件失去鼠标焦点时立即触发的问题,这会导致视觉提示在获得焦点之前被隐藏。
关注点
视觉提示被添加到包含父控件的容器中,因此在初始化视觉提示之前,父控件已添加到容器中非常重要。
图像的文件处理有点原始,应用程序要求它们与应用程序运行的文件夹相同,并且必须命名为 Image0.jpg 和 Image1.jpg。
我不太确定的一件事是,C# (或任何 .NET) 应用程序是否会因窗体上的控件太多而受到影响,我知道 Visual Basic 有一个限制。我的库显然鼓励您添加更多控件。
