65.9K
CodeProject 正在变化。 阅读更多。
Home

扩展(继承)的列表框和组合框控件版本

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.98/5 (18投票s)

2015年3月25日

CPOL

38分钟阅读

viewsIcon

62040

downloadIcon

2225

列表框和组合框控件的扩展版本,允许为单个项目提供图像、字体和颜色——列表框支持多行/对齐制表符——组合框支持下拉列表鼠标事件/水平滚动条和自定义下拉按钮。

 

最后更新:2024年8月30日 晚上11:15 (EST)

(注意:如果您在2021年8月24日 上午1:00 EST 之前下载过此文件,请阅读下面的“警告!”部分。此外,如果图形设计器“拒绝”显示包含一个或两个这些控件的窗体,请阅读下面的“在宿主项目中使用此库”部分。)

引言

ExtListBoxExtComboBox 分别继承自 ListBoxComboBox 控件——并具有以下附加功能:

  1. 允许在单个列表项的文本之前(或代替文本)显示图像,以及设置单个项的文本和背景的字体和颜色。
  2. 允许为给定的列表项提供多行文本(只需在项的文本中嵌入回车/换行符序列)。
  3. 允许使用一个命令智能地对齐(以制表符分隔)列表项的列(仅限 ExtListBox)。
  4. 允许自定义选定(高亮)项使用的文本和背景颜色。
  5. 允许捕获 ExtComboBox 下拉列表的鼠标事件并提供水平滚动条,以及自定义其下拉按钮的位图。
  6. 允许跟踪 ExtListBox 插入符号(caret)所在的项目,无论它是否被选中(高亮)。
  7. 允许基于显示字符串对列表项执行二进制搜索;在排序列表上可以使用 FindStringBinarySearch 代替 FindStringFindStringExact
  8. 允许设置列表,以便在列表更改时自动调整水平滚动范围和制表符对齐。
  9. 如果需要,允许在设计时设置列表初始内容中每个项的文本和所有图形属性。

最近更改

2024年8月30日 晚上11:15 (EST)

BindingContextDataBindings 属性不再被隐藏(Shadowed),因为我发现它们不需要特殊处理。因此,您现在可以使用这些属性 DataSource 属性将 ExtListBoxExtComboBox 控件绑定到数据源。

2023年2月2日 (土拨鼠日!)

COMBOBOXINFO 结构(在 ExtComboBox.ExtComboBoxNativeWindow 嵌套类中)现在是一个类。同时,为控件的 ObjectCollection 对象提供了各种构造函数(类似于其中 AddRange 方法的重载)。

2023年2月1日 下午2:30 (EST)

ExtComboBox 类不再依赖 Win32 API SetWindowSubclassRemoveWindowSubclassDefWindowProc 来对下拉列表进行子类化;相反,它使用一个嵌套的 Private 类——ExtComboBoxNativeWindow,该类继承自 NativeWindow——以完全托管的方式处理子类化。下拉列表的4个鼠标事件仍然按原样工作;将编辑和下拉窗口句柄以及将消息信息转换为 MouseEventArgs 信息的所有关键代码都已转移到嵌套类中,以及检测控件的创建/销毁的主句柄。

此外,我修复了演示程序中的一个错误,以便鼠标状态报告过程对所有4个 DropDownMousexxxxx 事件(正如应该的那样)都触发,而不仅仅是 DropDownMouseMove。当我移除然后重新添加控件到窗体上,但忘记在重构的 Handles 子句中包含所有4个事件时,就会出现这个错误!

9月24日 下午1:50 (EST)

我修正了一个拼写错误,该错误导致 ExtComboBox 属性 DropDownButtonRectangle 被错误地命名为 DropDownButtonRectange(!!)。如果您已在代码中使用此拼写错误的属性,则在下载已更正的 DLL 后,请在所有使用它的地方添加“l”。

2002年9月13日

我终于添加了一个属性页,允许程序员在设计时填充任一控件的列表!!!我还修改了 ExtListBox.IntegerCollectionAlignTabs 方法,使其能够使用每列的最小必要制表符宽度(包括列间距),或者当制表符不够宽时简单地扩展制表符(之前的行为)。我还修改了 ExtListBox.HorizontalExtentExtComboBox.DropDownHorizontalExtent,当设置为-1时(不再是瞬时值),水平滚动条的水平范围会在列表修改时自动调整,并添加了 ExtListBox.SpacingBetweenColumns 属性,以允许在列表修改时自动调整制表符对齐。此外,ItemHeight 即使在运行时设置为 0-255 之外的值,也会抛出异常,并且 ExtComboBox.IndexFromDropDownPoint 有一个额外的可选参数(在两个重载上)来指定是否自动滚动下拉列表到指定的坐标。最后,我修正了项目渲染和制表符对齐过程中的一些错误,并为各种集合类添加了一系列构造函数。

2022年4月12日 下午2:49 EST (非常重要!)

我修复了 ExtListBoxItemHeight 属性中的一个错误,该错误导致控件在设置新值后无法反映该值(尽管仍在后台设置了项目高度)。对于两个控件,请参阅属性的新描述以及何时设置它的注意

2021年12月28日

我修正了受保护的 OnCaretIndexChanged 方法声明中的一个错误,使其现在可以被重写。

2021年12月25日 (圣诞快乐!!!) 下午5:30 EST

隐藏的 ItemInfo 属性 DisplayString 和 ItemInfo 类的公共方法 ToString 都返回列表项的最终显示文本字符串,除非 ItemInfo 实例不是从实际列表中检索的(即,由宿主程序显式实例化),在这种情况下,它只是 Value.ToString

2021年12月22日 下午4:50 EST

我在两个控件中都添加了 FindStringBinarySearch 方法,允许使用二进制搜索来搜索已排序列表中的完全匹配或部分匹配的显示字符串;这对于非常大的列表很有用。我还处理了一些潜在的罕见错误情况。特别是,ItemInfo 的“隐藏” DisplayString 属性总是尽可能地解析对象的最终显示文本,并且解析 DisplayMemberValueMember 属性信息的 ExtSupportModule 过程会解析声明存在歧义或不存在的属性的情况。

如果 DisplayMemberValueMember 指定的属性对于列表对象不存在,则控件的行为就像没有指定属性一样——分别返回整个对象的 ToString 值或整个对象本身。如果属性隐藏了基类版本,则它依赖于派生类版本。如果在考虑了任何隐藏后,仍有两个或多个属性重载,则控件的行为就像没有指定属性一样(返回默认信息)。(在任何情况下,由于请求的属性有歧义或不存在,都不会向宿主程序抛出异常。)

2021年10月17日 (非常重要!)

我修复了一个导致在没有图像且 ImageSize 未设置为 Size.Empty 时控件崩溃的错误。

2021年8月24日 上午1:00 EST (非常重要!)

我修复了一个潜在的文件和文件夹故障,该故障可能——可能——导致您依赖一个不支持最新功能的过时 DLL。(请参阅“警告!”部分修复您在2021年8月24日 上午1:00 EST 之前下载的情况!)此外,两个控件中的 SelectedItemInfo 属性不再是只读的。(这是我的错误!)将其设置为 ItemInfo 实例将,如果 ItemValue.Value 对象存在于列表中,则选择该条目并将图像、字体和颜色属性设置为您提供的实例。

2021年8月20日

我修复了演示程序中的一个错误,该错误导致在鼠标悬停在不带水平滚动条的组合框的最底部项目上时,工具提示不会显示。(请参阅文章末尾的 ShowExtComboBoxTooltip 代码示例进行修改。)

2021年6月23日

演示程序的小更新——它现在显示了如何在 ExtComboBox 的下拉列表中显示项目工具提示!!演示中的 ShowExtComboBoxTooltip 过程处理所有事情。请注意,如果坐标(相对于编辑部分或下拉框)被省略,则使用最新的坐标。如果包含了 AreForcingRedraw 且其值为 True,则即使鼠标和选择未移动,工具提示也会重绘;否则,仅当鼠标位置或选定索引更改时,工具提示才会重绘。演示还为 ExtListBox 提供了工具提示,指示当前插入符号索引。请注意,列表框使用 ToolTipSetToolTip 方法(标准过程),而组合框必须依赖 Show 方法(显示默认的 5 秒!)。

2021年6月3日

ExtComboBox 的辅助句柄子类化中加入了异常处理,以确保即使在“DropDown”事件过程中未处理异常时,也会发生默认的消息处理;此外,使焦点矩形绘制逻辑更有效。

2021年5月22日

我修正了一个错误,该错误导致控件在 DropDownStyleComboBoxStyle.Simple 时,读取 DefaultDropDownButton 时崩溃,并在设置 CustomDropDownButton 时可能显示错误。(请参阅下面成员的更新描述。)

2021年5月20日 下午9:49 EST

我更新了两个控件的 SelectedValue 属性的代码,以便 SelectedValueChanged 事件在正确的情况下触发。此外,ExtListBox 控件现在包含一个 CaretIndex 属性和 CaretIndexChanged 事件,用于跟踪列表框插入符号所在的项目;这在 SelectionModeMultiSimpleMultiExtended 时很有用。最后,我修正了 ExtSupportModule 模块的 DrawImageAndText 方法中的逻辑,以便当前插入符号下的项目具有正确的焦点矩形。

2021年5月5日

我使用了 Win32/SetWindowSubclass(现在是嵌套的 NativeWindow 派生类——**见上文**)和 WndProc 子类化,以允许跟踪 ExtComboBox 下拉列表的鼠标事件(DropDownMouseMoveDropDownMouseDownDropDownMouseUpDropDownMouseWheel)——以及利用它们提供的信息的属性和方法——为列表启用水平滚动条(DropDownHorizontalScrollbar/DropDownHorizontalExtent),并允许用自定义位图替换默认的下拉按钮。对下拉列表进行子类化是一件棘手的事情,需要“非托管”Win32 API,因为列表使用与整体控件不同的、不直接暴露的句柄。我还暴露了下拉和编辑部分句柄,以防您希望使用 Win32 和子类化进行其他扩展。这些新属性、方法和事件中的许多可能不经常使用,但它们可能很有用——特别是能够跟踪下拉列表上的鼠标。请注意,所有专门针对下拉列表的自定义成员在其名称中都包含“DropDown”。

2020年12月19日

我修复了一些关于没有类型规范(声明末尾没有“As type”子句,导致某些属性被错误地定义为 Object 类型)的属性和函数,以及一些关于隐式类型转换的错误。因此,类库将能够正确地使用Option Strict进行编译(现在是这样);如果您一直在使用这些控件在一个编译了 Option Strict 的宿主应用程序中,并遇到有关类型转换的编译时错误,这应该可以解决这些问题!!!

2020年12月17日(文档修复)

不是功能更改或错误修复;但是——我错误地表示 DataSource 在设计时不可用。实际上的。

2020年12月14日

一个新属性 AlignText,允许文本部分项的起始位置在最宽图像的右侧之后开始,即使图像大小不是固定的(即,当 ImageSize = Size.Empty 时)。

2020年12月10日

以前,控件设计为“数据感知”;现在,支持 DataSourceDisplayMemberValueMember 属性,以及一个新方法 SetDataSource,该方法允许使用图形信息与数据源进行绑定。但是,这些属性在扩展控件与基类控件中的实现方式有所不同。MyBaseDataSource 信息与派生控件的不同,并且 DisplayMemberValueMember 属性与 MyBase 完全不使用。与基类控件一样,当 DataSource 不是 Nothing 时,宿主程序无法在列表中插入、删除或修改数据;但是——与基类控件不同——它可以修改列表项的图形信息,甚至可以设置 Sorted 和/或 DisplayMember 属性来更改显示项的顺序并由 Items 集合返回,而 DataSource不是 Nothing。但是,通过引用 DataSource属性返回的项的顺序不受影响——因此程序不应仅依赖整数索引来匹配列表项与数据源项。然而,使用 BindingContextDataBinding 属性进行数据绑定仍然不受支持;这两个属性都被重写/隐藏为只读属性,返回Nothing

最后,现在可以设置列表项的背景颜色,以及图像、字体和文本颜色;并且可以更改用于高亮项的文本/背景颜色。此外,DrawItemMeasureItem 事件不再被“忽略”(抑制),从“宿主程序”的角度来看;然而,任何特定于这些控件的“默认”绘制或测量总是在宿主程序可以使用给定的事件进行附加显示格式化之前完成。

Using the Code

关于在填充列表时指定图形信息

ExtListBoxExtComboBox 及其 ObjectCollection 类的许多成员支持重载,允许宿主程序为正在添加到/分配给列表的项指定图像字体文本颜色背景颜色信息。每个参数都是可选的,默认为父控件的 DefaultImageFontForeColorBackColor 属性。每个参数,如果已指定,可以是标量实例 ImageFontColorColor——在这种情况下,给定类型的相同图形信息适用于所有指定的列表项——或者是这些类型的数组——在这种情况下,不同的图形信息将分配给每个指定的列表项。后一种情况,数组会自动调整大小以匹配要添加/分配的项目数量,而与数组元素对应的项目(这些元素缺失或为 Nothing)将获得上述默认值。(数组元素必须与按索引枚举的列表项顺序相同。)

请注意,数组只能与用于添加/分配范围的成员一起指定,例如 Items.AddRangeSetDataSource——不能与用于添加单个项的成员一起指定,例如 Items.AddItems.Insert——因为为单个项分配多个图像/字体/颜色没有意义。最后,有重载用于使用 ItemInfo 类型实例或数组/集合,以便在调用成员之前预先指定图形信息——从而避免使用额外的参数或默认值。

使用基类/祖先类类型变量/参数时的成员使用

由于控件及其相关类重写和/或隐藏了许多基类成员——其功能与 MyBase 版本非常不同——因此在将这些类的实例分配给键入为基类或祖先类的变量/参数时,应非常小心。最好的做法是先将变量/参数(使用 CTypeDirectCast)转换为派生版本,然后再调用可能被重写或隐藏的成员,以免调用基类版本,从而产生不良后果。例如

Public Function GetDisplayMember(lb As ListBox) As String
'   get DisplayMember value for list box
If TypeOf lb Is ExtListBox Then
   '   extended control
   Return _
      DirectCast(lb, ExtListBox).DisplayMember
 Else
   '   regular control
   Return lb.DisplayMember
End If
End Function

在宿主项目中使用此库(请阅读!)

我现在添加了一个属性页/编辑器,允许程序员在设计时设置和修改列表的初始内容——这是一个以前无法实现的功能,在两个控件的基类中都存在。但是,由于我不知道如何编写“生成代码的代码”,因此该功能与基类中的实现方式不同,它依赖于一个“代理属性”(InitialListItems),该属性出现在属性窗口中,显示为“Items”(它修改的是这个属性),并且只能在运行时设置为空列表(即,在窗体的 InitializeComponents 方法中)。由于此属性的类类型性质(不知道为什么这是一个问题),您在 Visual Studio 中尝试从一个项目/解决方案切换到另一个使用这些控件的(预先存在的)项目/解决方案时可能会遇到问题。

当您要定位的项目/解决方案是全新的(从头创建)、预先存在的且是 VS 当前会话中加载的第一个,或者预先存在的但尚未在任何窗体上使用这些控件中的任何一个时,您应该不会遇到问题。但是,如果您从一个项目/解决方案切换到一个已经在其中一个或多个窗体上使用这些控件的预先存在的项目/解决方案,那么您不能只是关闭第一个项目/解决方案然后打开包含这些控件的那个;相反,您必须完全退出 VS,然后重新启动它并加载目标项目/解决方案。否则,任何使用任一控件的窗体都将无法在图形设计器中成功显示!如果您计划将一个使用这些控件的预先存在的项目添加到(尚未包含这些控件的)一个预先存在的解决方案中,那么请将项目添加到解决方案,保存解决方案,退出 VS(完全退出),然后重新启动它并加载已修改的解决方案。

对于由此带来的任何不便,我们深表歉意。

自定义这些控件(请阅读!)

如果您希望自定义此类库,除非您在使用图形设计器对属性页窗体(frmListCollection)或其任何控件进行任何更改,否则不应有任何问题。在这种情况下,您必须在进行任何更改后执行以下操作:打开窗体的资源文件(ListCollection.resx),并在“Other”类别下,删除“elbList.InitialListItems”的行(在出现的警告时响应“Yes”);然后打开其设计器代码文件(ListCollection.Designer.vb),并删除或注释掉以“elbList.InitialListItems = ”开头的行。否则,库项目将无法生成!这都与该窗体使用了在同一库中定义的两个控件之一的事实有关。

ExtListBox 和 ExtComboBox 控件的自定义成员

ExtListBoxExtComboBox 分别继承自 ListBoxComboBox。下面是独有于这些控件,或者功能与其基类不同的属性、方法和事件。

* = 成员在基类控件中不可用
† = 属性在设计时不可用

属性

  1. CaretIndex *†(仅限 ExtListBox)—— 获取或设置列表框插入符号所在的项目,无论项目是否被选中(高亮)。当允许多选时很有用。读取此属性时,返回当前选定项目的索引,如果 SelectionModeSelectionMode.OneSelectedIndex 不为 -1;——否则,使用 SendMessage Win32 API 来获取当前(可能未选定)的插入符号索引(如果没有项目获得焦点,则返回 0)。写入此属性时,还会选择指定索引的项目(如果不是 -1),或取消选择所有项目(如果为 -1),如果 SelectionModeSelectionMode.One(且列表为空);——否则,使用 SendMessage API 将插入符号设置到指定索引而不影响任何选择。当控件没有项目,或者在 SelectionMode 不是 SelectionMode.One 时缺少句柄时,获取时返回 -1,设置时不执行任何操作
  2. Items——指定列表项,包括图形信息。请注意,此类型为 ExtListBox.ObjectCollectionExtComboBox.ObjectCollection,而不是它们的基类型。要在设计时设置列表内容,请参阅 InitialListItems 属性以及下面关于相应属性页的主题。
  3. SelectedItems † 和 SelectedIndices †(仅限 ExtListBox)——分别指定选定的项目(包括图形信息)及其索引。请注意,这些类型为 ExtListBox.SelectedOnjectCollectionExtListBox.SelectedIndexCollection,而不是它们的基类型。
  4. DrawMode——根据 ExtListAndCombo.DrawMode 枚举值指定要具有固定或可变垂直项目高度的位置。(控件始终配置为“所有者绘制”以允许图形操作,因为控件执行其自身的自定义成像。如果您尝试将 DrawMode 设置为 DrawMode.Normal,则会抛出异常。)
  5. DisplayMode*——根据 ExtListAndCombo.DisplayMode 枚举值指定是仅显示文本、仅显示图像还是两者都显示(图像在左,文本在右)。
  6. AlignText*——指定是否将项的文本部分的水平对齐起始位置放在列表中最宽图像的右端之后,即使图像大小不是固定的(ImageSize = Size.Empty)。True 是默认值;如果设置为 False,则项文本的水平起始位置可能随图像宽度而变化,因为每项的文本然后从其特定关联图像的右端开始。
  7. ImageSize* 和 ImagePadding*——分别确定显示图像的 SizePadding;默认为方形图像,四周有 1 像素的填充,使用初始 ItemHeight 属性值(减去填充)进行大小调整。如果 ImageSize 设置为 Size.Empty (0,0),则图像不会缩放到匹配 ImageSize:在这种情况下,如果 DrawMode 属性为 ExtListAndCombo.DrawMode.UseFixedHeight,则它们将被缩放到使其高度与当前 ItemHeight 属性值(减去填充;保持纵横比)匹配;如果 DrawMode 属性为 ExtListAndCombo.DrawMode.UseVariableHeight,则它们根本不会缩放。(后者在图像大小不同时很有用;使用 AlignText 来确定项目文本的左端是否所有项目都对齐。)每当在设计时更改 ItemHeight 值时(通过在属性窗口中设置它或调整控件大小),这两个属性都会被重置为四周填充 1 像素,并使用方形 ItemHeight 减去填充的大小调整。(在运行时更改 ItemHeight不会发生此行为。)
  8. ItemHeight——获取第一个项目的高度;当 DrawmodeExtListAndCombo.DrawMode.UseFixedHeight 时设置项目的高度,或当 ExtListAndCombo.DrawMode.UseVariableHeight 时设置下一个添加的项目的高度。在设计时设置时,会设置 ImageSizeImagePadding,如上所述。注意:设置此值时,应在更改项目的图形属性之前进行,因为出于未知原因,设置它会重置所有项目的字体为主要的 Font 属性!最好在列表为空时设置它,至少对于 ExtListBox 控件而言,因为在填充列表时这样做可能会导致控件的 Height 收缩(这也是基类控件的问题!)。
  9. DefaultImage*——指定在没有为列表项指定图像时显示的 Image;默认为无图像。
  10. SelectedItemInfo*†——获取或设置选定列表项的完整信息(包括图像/字体/颜色),作为 ItemInfo 实例。设置此属性将,如果存在匹配实例 Value 属性的条目,则选择该条目并将图像、字体和颜色属性根据新实例进行设置。
  11. DisplayMember——指定列表项数据对象(ItemInfo.Value)的哪个(子)成员用于在列表中显示;如果设置为 null(默认)或不存在的成员,则显示该对象 ToString 方法的值。与基类版本不同,此属性即使在 DataSource 不为 Nothing 时也可以设置,并且如果 Sorted 属性值为 True,则会影响显示和 Items 集合中的项目排序顺序(但不会影响 DataSource 属性本身)。
  12. ValueMember——指定列表项数据对象的哪个(子)成员由 SelectedValue 属性返回;如果设置为 null(默认)或不存在的成员,则 SelectedValue 返回该对象 ToString 方法的值。与基类版本不同,此属性即使在 DataSource不是 Nothing 时也可以设置。
  13. Sorted——确定列表在添加、删除或修改项目时是否自动排序;当设置为 True 时,列表会立即排序。排序顺序取决于 DisplayMember 属性的值以及是否使用了 Format 事件(用于为项目指定自定义字符串)。与基类版本不同,此属性即使在 DataSource设置为 Nothing 时也可以设置;但是,重新排序显示/Items 列表不会影响 DataSource 引用中的项目顺序。
  14. HighlightTextColor* 和 HighlightBackColor*——分别指定分配给高亮项目的文本和背景的颜色。(当标准“高亮”颜色用于未高亮项目时很有用。)
  15. DataSource——使用默认图形信息检索、分配或插入列表中的项目。
  16. HorizontalExtent(仅限 ExtListBox)——通过将其设置为-1,允许自动确定列表中最宽项目的宽度并据此设置范围——在这种情况下,任何添加、删除或修改列表项都会导致重新计算该值并将其重置为反映最宽的新项目。ExtListBox.IntegerCollectionAlignTabs 方法现在将此属性设置为-1,以智能地设置范围。(旧方法未能考虑到我所做的对图像大小调整选项的更改。)现在设计时也可用。
  17. DropDownHorizontalScrollbar* 和 DropDownHorizontalExtent*(仅限 ExtComboBox)——功能上与 ExtListBoxHorizontalScrollbar / HorizontalExtent 相同,不同之处在于它们用于为 ExtComboBox 的下拉列表实现水平滚动条功能。与列表框控件一样,第二个属性仅在第一个为 True(允许水平滚动条)时才有意义,将其设置为-1 会使控件将其设置为最宽项目的范围,并在对列表进行任何更改时重新评估该范围。DropDownHorizotnalExtent 现在也可用在设计时。
  18. CustomDropDownButton*(仅限 ExtComboBox)——为 ExtComboBox 的下拉按钮指定一个 BitmapNothing 表示正在使用默认图像);允许使用自定义位图设置图像。请注意,在读写此属性时,图像不会按按钮大小(DropDownButtonSize)存储,而是在渲染时缩放到适合(这可以防止控件反复调整大小时图像精度下降,例如在设计时);此外,与默认图像不同,自定义按钮的背景颜色不会根据列表是否下拉而改变。(因此,**在使用自定义按钮后恢复到标准按钮,请将此属性设置为Nothing而不是 DefaultDropDownButton**;否则,您只会得到一个自定义图像的副本,并且其外观不会随按钮的状态而改变!)自定义下拉按钮,就像默认按钮一样,在设计为“下拉”的列表时渲染;也就是说,只要 DropDownStyle 不是 ComboBoxStyle.Simple
  19. DefaultDropDownButton*†(仅限 ExtComboBox)——获取组合框控件当前“默认下拉”按钮的 Bitmap——确切的位图取决于下拉样式和按钮的状态。此属性仅在控件具有句柄时返回有意义的值,读取时使用自定义按钮可能会导致短暂闪烁,因为默认按钮会暂时恢复以便读取到位图中。此属性主要用于允许您将默认图像用作创建自定义图像的绘图模板。当 DropDownStyleComboBoxStyle.Simple 时返回Nothing,因为该样式的组合框不会“下拉”。
  20. DropDownHandle*† 和 EditHandle*†(仅限 ExtComboBox)——分别返回组合框的下拉列表编辑部分的句柄;与用于整体控件的 Handle 属性不同。这些句柄只有在整体句柄存在时才有有意义的值,并且专门提供给希望为控件的这些部分创建自己的特殊功能的情况。
  21. BindingContextDataBinding——隐藏的只读属性,返回Nothing。请使用 DataSource 属性或 SetDataSource 方法使控件具有数据感知能力!
  22. SpacingBetweenColumns*(仅限 ExtListBox)——导致 ExtListBox.IntegerCollectionAlignTabs 方法在每次列表内容更改时被调用,以便所有制表符都足够宽以容纳每列中最宽的项目加上此属性指定的像素数。设置为-1禁用自动重新对齐。
  23. InitialListItems*——“代理属性”,允许在设计时设置列表的初始内容!它在属性窗口中显示为“Items”(它修改的属性),并且可以在设计时设置任意次数。然而,在运行时,它只能在列表为空时设置。您唯一想在非设计器生成的代码中设置它的情况是当您在运行时动态创建控件时(否则窗体的 InitializeComponents 方法将设置它)——在这种情况下,使用 Items 属性填充它更简单。有关属性页和 ItemInfoCollection 类的主题,请参阅下方。 (顺便说一句,仅仅操作该类的实例不会填充列表;该实例必须分配给此属性。该属性的设置故意使得 Intellisense 在代码编辑器中提示它;但它仍然存在——并在代码中包含它不会导致编译器错误。)

方法

  1. SetDataSource(datasource[, images][, fonts][, textcolors][, backgroundcolors])*——设置 DataSource 属性,并为数据源中的项分配特定的图形信息
  2. DropDownRectangle[(displayrectangle)]* 和 DropDownSize[(displaysize)]*(仅限 ExtComboBox)——分别检索组合框下拉列表的 RectangleSize——如果提供了可选参数且其值为True,则为屏幕/完整坐标/尺寸;否则仅为客户区坐标/尺寸。
  3. DropDownPointToScreen(point)* 和 DropDownPointToClient(point)*(仅限 ExtComboBox)——分别进行组合框下拉列表上点的客户区到屏幕和屏幕到客户区的转换。
  4. IndexFromDropDownPoint(point[, autoscroll])* / IndexFromDropDownPoint(x, y[, autoscroll])*(仅限 ExtComboBox)——与列表框控件的 IndexFromPoint 方法相同,不同之处在于它获取下拉列表客户区坐标点下的项目的索引。值为-1 表示该点不在列表的客户区内。如果 autoscrollTrue(默认),则下拉列表会自动滚动以显示该点。
  5. DropDownButtonRectangle* 和 DropDownButtonSize*(仅限 ExtComboBox)——分别以客户区坐标检索下拉按钮的 RectangleSize;当控件具有句柄时,这些属性才有意义。
  6. FindStringBinarySearch(searchstring[, exact]) *——定位列表中第一个显示字符串与指定 searchstring 完全匹配(exact = True 或省略)或部分匹配(exact = False;条目必须以 searchstring 开头)的条目,前提是显示字符串按升序字典顺序排序(通过将 Sorted 设置为 True 或手动排序列表)。如果找到匹配项,则返回第一个匹配项的索引。如果不存在匹配项,则返回一个负值,该负值是第一个显示字符串按字典顺序排在 searchstring 之后的条目的索引的 1 的补数(使用“Xor -1”获取索引);如果返回值的 1 的补数大于或等于列表的大小,则所有列表项的显示字符串在字典顺序上都 precedes searchstring。(在任何非匹配情况下,索引对应于在保持列表排序的情况下添加 searchstring 的正确插入点。)不要在处理 Format 事件的过程cedures中使用此方法,因为此时并非所有显示字符串都一定设置为其正确值。
  7. GetItemText(item) ——返回指定列表对象的显示字符串;此方法实现与基类不同,因为它反映了在处理任何 Format 事件之后的最终显示文本,前提是您不在处理此类事件的过程procedures中读取它。 返回的文本代表列表中第一个匹配的对象项;如果不存在这样的项,则抛出异常。

事件

  1. CaretIndexChanged*(仅限 ExtListBox)——当列表框插入符号(CaretIndex 属性)所在的项目索引发生变化时发生;在 SelectedIndexChanged 事件之后触发。
  2. DopDownMouseMove*、DropDownMouseDown*、DropDownMouseUp* 和 DropDownMouseWheel*(仅限 ExtComboBox)——跟踪组合框控件下拉列表的鼠标操作,只要列表已下拉。它们接受与其常规鼠标事件相同的参数——第二个参数为 MouseEventArgs 值——但坐标是相对于下拉列表客户区左上角的(而不是编辑部分的),e.Clicks 返回自控件创建以来下拉列表的点击次数,并且 e.Delta 仅对 DropDownMouseWheel 事件有意义。这些事件在列表下拉时响应鼠标活动——即使在列表客户区之外(使用 DropDownRectangle(False).Contains 检查坐标是否在客户区内)——并在任何“标准”组合框鼠标驱动行为之前触发。此外,它们增强但不会阻止标准行为——这就是为什么我没有为下拉列表创建“点击”和“双击”事件的原因。请注意,这些事件仅适用于列表,而不适用于编辑部分,无论 DropDownStyle 是否使列表“下拉”(ComboBoxStyle.DropDownComboBoxStyle.DropDownList)或“始终存在”(ComboBoxStyle.Simple)。

辅助类的自定义成员

ItemInfo 类

此类的实例包含列表项或潜在列表项的对象及其关联的图形信息。其 Public 成员如下:

  1. Value——列表项 Object 的属性。
  2. Image——要分配给列表项的 Image 属性。如果为 Nothing,则在将项分配或添加到列表时,默认情况下将分配基础控件的 DefaultImage 属性值(如果该属性也为 Nothing,则为无图像)。
  3. Font——显示项文本时使用的 Font 属性;默认为控件的 Font 属性。
  4. Color——项文本在未高亮时显示的前景色 Color 属性;默认为控件的 ForeColor 属性。
  5. BackColor——用于项的背景色 Color 属性;默认为控件的 BackColor 属性。
  6. ToString——项的实际显示文本方法;始终与“隐藏”属性 DisplayString 相同(见下文)——可以是 Value.ToString,可以是宿主控件的 DisplayMember 指定的属性ToString 文本(如果存在),或者是在宿主程序处理 Format 事件的处理器中设置的值。(如果 ItemInfo 实例尚未分配给实际列表,则有效地为 Value.ToString。)

该类还包含 2 个(Friend)属性,仅对类库(而不是宿主程序!)可用。

  1. DisplayString——应在列表中显示的字符串。如果显式设置为 Nothing(默认),则后续读取返回 Value.ToString——默认值——或者宿主控件指定的 ExtControl.DisplayMember 属性ToString 文本——假设 ItemInfo 实例已被分配给或从 ExtListBox/ExtComboBox 列表检索,并且 DisplayMember 是一个非空值,指定 Value 的有效属性(在其类自己的继承层级中具有唯一版本[请参阅上方关于更新的信息])。如果显式设置为实际字符串(即使是空字符串!),则后续读取返回该特定字符串。此属性仅作为宿主程序处理宿主控件的 Format 事件的结果而设置。(显式的“set”值是内部存储的值,而“get”值取决于该内部值以及 ExtControl.DisplayMember。)
  2. ExtControl——ExtListBoxExtComboBox 的一个实例,指定此 ItemInfo 实例被分配到的控件;在“规范化”项以供控件成员或其 ObjectCollection 成员使用时始终设置,在分配给列表之前始终为 Nothing。

ExtListBox.ObjectCollection 和 ExtComboBox.ObjectCollection 类(Items 属性)

这些类分别继承自 ListBox.ObjectCollectionComboBox.ObjectCollection。自定义功能如下:

  1. Item(index) 获取或设置底层 Object,对应于列表项(默认属性)ItemInfo(index) 获取或设置列表项的完整图形信息,由 ItemInfo 实例指定。(ItemInfo(index).Value = Item(index)。)
  2. AddInsert 功能重载,允许选择性地指定对象的图像、字体和/或文本/背景颜色;每个重载还有一个接受 ItemInfo 实例的重载,将列表项及其图形信息作为单个参数。
  3. AddRange 功能重载,接受 ItemInfo 数组——或接受一个 Object 数组或基类/派生类 ObjectCollection 实例,并带有可选的图像/字体/文本颜色/背景颜色参数。(如果主要参数是派生类 ObjectCollection,则图形参数是多余的(且被忽略),因为集合已经指定了图形信息。)
  4. CopyTo 根据指定的数组类型,将主要对象(ItemInfo.Value)信息复制到 Object 数组,或将完整信息(包括图像、字体和文本/背景颜色)复制到 ItemInfo 数组(当数组类型为 ItemInfo 时为完整信息)。
  5. ToArray 创建一个 ItemInfo 数组,包含列表项。
  6. 提供了构造函数重载,允许将集合与相应的父控件关联,并可选地提供 ItemInfo 数组,或带图形信息的 ObjectCollection 实例(在指定派生类 ObjectCollection 时被忽略),以指定初始内容。

ExtListBox.IntegerCollection 类(CustomTabOffsets 属性)

此类继承自 ListBox.IntegerCollection;其自定义功能如下:

  1. 制表符偏移量的 Item(index) 值以像素为单位指定,而不是对话框单位;偏移量相对于列表条目文本部分的开头。默认属性。
  2. AddRange 允许您指定一个 Integer 数组、一个现有的(派生类)IntegerCollection 或一个基类 IntegerCollection 作为其参数。(后一种情况,对话框单位将被转换,使用控件的整体“父”Font,转换为像素。)
  3. 提供了一个 AlignTabs([spacingbetweencolums][, expandonly]) 方法,该方法测量列表项中所有列的宽度,并创建/扩展制表符偏移量,以便所有相应的列水平对齐——假设所有文本项的左端由于图像宽度相同或控件的 AlignText 属性为 True(默认)而水平对齐。它还会设置控件的 HorizontalExtent 属性,以防启用了 HorizontalScrollbar。此方法接受一个可选的 Integer 参数,用于指定列之间的最小空格像素(spacingbetweencolumns,默认为1),以及一个可选的 Boolean 参数,用于指定是否仅在制表符不够宽以容纳所有项目对应的列和最小空格时才移动制表符(默认为False)。默认情况下,它将制表符设置为每列所需的最小宽度加上它们之间的最小间距——不仅扩展了太窄的制表符,还收缩了足够宽的制表符。注意:此方法将父控件的 HorizontalExtentUseCustomTabOffsets 属性分别设置为 -1True

与标准的 ListBox 控件不同,如果未指定自定义制表符,ExtListBox 不使用“默认制表符”。如果 UseCustomTabOffsetsFalse,或者未创建制表符偏移量,则文本中的任何制表符字符都将保持未扩展状态。

ExtListBox.SelectedIndexCollection 类(SelectedIndices 属性)

此类继承自 ListBox.SelectedIndexCollection,具有以下自定义功能:

  1. ObjectCollectionIndexOf(以前未记录)返回此集合中给定索引的项目的 ExtListBox.ObjectCollection 索引。基本上,它是 IndexOf 的反向操作,后者获取此集合中给定 ExtListBox.ObjectCollection 索引的项目的索引。
  2. ToArray 创建一个 Integer 数组,包含选定索引的列表。

ExtListBox.SelectedObjectCollection 类(SelectedItems 属性)

此类继承自 ListBox.SelectedObjectCollection,并具有以下自定义功能:

  1. ItemInfo(index),获取或设置列表项的完整信息,作为 ItemInfo 实例。
  2. CopyTo 将列表复制到数组——根据需要为主要对象(ItemInfo.Value)信息复制到 Object,或为完整信息复制到 ItemInfo
  3. ToArray 创建一个 ItemInfo 数组,包含选择列表。
注意

如果您使用“For Each variable ...”来枚举 ObjectCollectionItems 属性)或 SelectedObjectCollectionSelectedItems 属性),则每个 variable 的类型将是 ItemInfo,包含条目的完整信息。使用 variable.Value 访问底层 Object

设计时设置列表

已创建一个名为 InitialListItems 的“代理属性”,以允许在设计时设置 Items 属性集合的初始内容。(终于!!)只需转到属性窗口中名为“Items”的属性,然后单击省略号 [...] 按钮。属性页如下所示:

它包含一个 ExtListBox 来显示父控件的列表外观(如果父控件是 ExtComboBox,则在列表下拉时显示)——将父控件的 ItemsAlignTextDefaultImageImageSizeImagePaddingFontForeColorBackColorDrawModeItemHeightHighlightTextColorHighlightBackColor 属性传递给属性页的列表框。(属性页列表框可以根据需要水平滚动,即使父控件没有设置为可滚动。)

每当在列表框中选择一个项目时,右侧的属性网格将显示选定项目的 ItemInfo 属性 BackColorColorFontImageValue(始终为未制表符分隔的文本)以供修改。修改属性时,对项目的影响会立即在列表中体现。

Add 按钮在选定项之后插入一个新空白条目(并将焦点切换到网格以便进行修改),Remove 按钮删除选定条目,箭头按钮将选定条目向上或向下移动列表。要将焦点设置到现有项目的网格,请双击该条目(或在选择条目后按 Tab 键切换到网格——或按Ctrl+G)。要查看选定项目的真实文本和背景颜色而不移开焦点,请取消选中“高亮选定项”,以便仅通过虚线焦点矩形来指示项目的选定状态;重新选中它以恢复正常高亮。

列表框和属性网格都具有上下文菜单。列表框的功能与 Add、Remove 和箭头按钮相同,还有一个“转到网格”选项,用于将焦点设置到选定列表条目的网格(与双击项目相同)。其快捷键如下:Ins = AddDel = RemoveAlt+[Up Arrow] = Move UpAlt+[Down Arrow] = Move Down,以及 Ctrl+G = Go To Grid

属性网格的上下文菜单(仅在突出显示属性的名称而非其值时有效!)允许撤销或重做自最近一次选择条目以来的一项或多项更改,或将一项或所有属性设置为“原始”值(最近一次选择条目时的值)或“默认”值(插入条目时的值——继承自父窗体的主要属性)。其快捷键如下:Ctrl+X = Undo changeCtrl+Y = Redo ChangeCtrl+Shift+O = Use original value for ALL properties,以及 Ctrl+Shift+D = Use default value for ALL properties

ItemInfoCollection 类

InitialListItems 属性的类型为 ItemInfoCollection,它继承自 Collection(Of ItemInfo),并具有以下自定义功能:

  1. 构造函数重载,用于指定父控件和可选的 ItemInfo 数组或预先存在的 ItemInfoCollection 实例。
  2. AddRange 方法,允许将 ItemInfo 元素数组追加到集合中。

请记住,修改集合不会影响列表直到它被分配给 InitialListItems 属性——在设计时使用上述属性页,或在运行时列表为空时(例如,在窗体的 InitializeComponents 方法中)。

代码片段

'   Get namespace
Imports ExtListAndCombo



Private Sub ThisProcedure()
'   ExtListBox
'   set up information for a list item
Dim ItemInfo As ItemInfo = New ItemInfo("Multi-line" & ControlChar.CrLf & "text", _
   ImageList1.Images.Item(0), New Font("Arial"), Color.Red, Color.Blue)
'   add 1 item
ExtListBox1.Items.Add(ItemInfo) ' specify all info at once
ExtListBox1.Items.Add(Value, Image, Font, TextColor, BackColor) ' specify separetly
'   add multiple items
Dim Values() As SomeType, ItemInfos() As ItemInfo
ExtListBox1.Items.AddRange(ItemInfos)
ExtListBox1.Items.AddRange(Values, Image, Font, TextColor, BackColor) ' same graphic info
Dim Images() As Image, Fonts() As Font, TextColors() As Color, BackColors() As Color
ExtListBox1.Items.AddRange(Values, Images, Fonts, TextColors, BackColors) ' different graphics
ExtListBox1.Items.AddRange(Values, Image, Fonts, TextColors, BackColor) ' some info same/some not
ExtListBox1.Items.Add("Column 1, Row 1" & vbTab & "Column two, Row two" & vbCrLf _
   & "Column one, Row two" & vbTab & "Column 2, Row 2")  ' use default graphics
'   handle tabs
ExtListBox1.CustomTabOffsets.AlignTabs(3) ' line up columns with at least 3 pixels between them
ExtListBox1.CustomTabOffsets.AlignTabs(3, True) 'same thing, but don't contract over-wide columns
' auto-adjust horizontal extent and tabs, with 5 pixels between columns as list changes
ExtListBox1.HorizontalScrollbar = True : ExtListBox1.HorizontalExtent = -1
ExtListBox1.SpacingBetweenColumns = 5 
'   display images of different sizes, but keep text aligned
ExtListBox1.ImageSize = Size.Empty : ExtListBox1.AlignText = True

'   ExtComboBox
'   set up defaults
ExtComboBox1.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList
ExtComboBox1.DrawMode = ExtListAndCombo.UseVariableHeight
ExtComboBox1.DisplayMode = ExtListAndCombo.DisplayMode.ShowImageAndText
'   handle data
ExtComboBox1.Sorted = True : ExtComboBox.DisplayMember = "ThisMember"
ExtComboBox1.SetDataSource(Data, Images, Fonts, TextColors, BackColors)
'   manipulate info
ExtComboBox1.DefaultImage = ImageList1.Item(2)
ExtComboBox1.Items.ItemInfo(Index) = ItemInfo ' set all info for an item
ExtComboBox1.DroppedDown = True ' display list
'   handle drop-down list, with horizontal extent auto-adjusting for list changes and custom button
ExtComboBox1.DropDownHorizontalScrollbar = True : ExtComboBox1.DropDownHorizontalExtent = -1
ExtComboBox1.CustomDropDownButton = ThisBitmap
'   binary search
Dim index As Integer = ExtListBox.FindStringBinarySearch(ThisString)
If index < 0 Then
   '   item not present--insert it
   index = (index Xor -1)
   ExtComboBox1.Insert(index, ThisString)
End If
ExtComboBox1.SelectedIndex = index
End Sub



'   mouse event for drop-down list!

Private Sub ExtComboBox1_DropDownMouseMove(sender As Object, _
   e As MouseEventArgs) Handles ExtComboBox1.DropDownMouseMove
'   get text of item being hovered over
With ExtComboBox1
   Dim Index As Integer = .IndexFromDropDownPoint(e.X, e.Y)
   If Index = -1 Then
      Label1.Text = "no item hovered over"
    Else
      Label1.Text = .Items(Index)
   End If
End With
End Sub

 

警告!

如果最新功能似乎不受支持,或者您在2021年8月25日 上午1:00 EST 之前已经下载过此文件,请执行此操作

检查“bin”文件夹——它间接包含 DLL 的调试和/或发布版本——是否存在于2 个父文件夹中。如果一个直接位于顶级文件夹(例如,“ExtListAndCombo”)内,而另一个位于其“ExtListAndCombo”子文件夹(例如,“ExListAndCombo\ExtListAndCombo”)内,那么第一个文件夹包含一个过时版本的控件,而第二个文件夹包含正确最新的版本。您需要删除第一个(直接位于顶级文件夹中的“bin”文件夹),并改用第二个(多一级深度的那个——整体 DLL 路径为“topfoldername\ExtListAndCombo\bin\debugorrelase\ExtListAndCombo.dll”,其中topfoldername 是顶级文件夹名称(默认也为“ExtListAndCombo”),debugorrelease 是“Debug”或“Release”)。

此外,您需要为之前创建的每一个使用 ExtListAndCombo.dll宿主项目执行此操作:打开它,并在“References”选项卡下检查 DLL 的源路径。如果路径包含“ExtListAndCombo”实例(位于顶级文件夹和“bin”之间)(即,它是“ExtListAndCombo\bin”而不是“ExtListAndCombo**\ExtListAndCombo**\bin”),您必须删除引用,使用正确的(更长的)路径重新添加,然后重新生成项目。任何关于缺失或已修改功能的编译时(或运行时)错误应该就会消失。(然后检查您的代码,看看是否移除了任何事件过程的“Handles”子句,并且需要重新添加。)

注释

  1. 如果您使用了不同的顶级文件夹名称来解压缩下载文件,那么请将上面所说的解释为,上层“ExtListAndCombo”变成了那个不同的名称,而下层“ExtListAndCombo”仍然是“ExtListAndCombo”。(指出这一点就像从婴儿手中抢糖果,但有些人可能匆忙中过于字面理解。)
  2. 如果您在2021年8月25日 上午1:00 EST之后首次下载本文档,那么您可以忽略所有这些。我已经修复了文件和文件夹的冗余故障!

关注点

为了确保列表中的项目及其各自的图形信息在对列表进行更改时保持同步,完整信息被塞入一个 ItemInfo 实例,这是 MyBase.ItemObjectCollection 中看到的内容。此外,此项目严重依赖继承、重写和(特别是)隐藏预先存在的成员,以插入自定义功能。

值得注意的是,虽然最终用户看到了并使用了这些控件的派生类的集合,但 CLR 看到并使用了其类的集合。因此,相应的(派生和基类)集合必须同步才能使“后台”工作正常运行。为了方便这一点,ObjectCollectionSelectedIndexCollection(仅限 ExtListBox)和 SelectedObjectCollection(仅限 ExtListBox)类在其构造函数中接受父控件作为参数,并依赖内部 BaseCollection 函数过程,这些过程返回 DirectCast(control, baseclass).ItemsDirectCast(control, baseclass).SelectedIndicesDirectCast(control, baseclass).SelectItems,分别供其成员代码使用。

注释

  1. 为了确保底层基类控件根据(扩展控件的)SortedDisplayMember 属性的值正确排序和显示项目,MyBase 在其自身的 Items 集合的每个 Item 中(派生集合中的 ItemInfo)存储了完整的图形信息,其中 ToString 方法表示对象本身或指定(扩展控件的)DisplayMember 成员的 ToString 方法。此外,DataSource后台的调用方式与 MyBase 不同于派生控件——后者也不DisplayMemberValueMember 属性的读写传递给 MyBase

  2. 控件的 FindStringFindStringExact 方法被隐藏(shadowed)以修复基类控件中的一个已知错误,该错误会导致当起始索引等于最后一个项目时抛出异常。派生类版本使用 -1(列表开头)的索引,只要指定索引是最后一个项目,从而避免了异常。

  3. 此版本已更新,以修复当允许多选时涉及 SelectedIndicesSelectedItem 属性的错误(参见上方更多内容)。
  4. ExtComboBox 控件类现在包含大量的子类化逻辑(全部在源代码的早期部分),同时使用了“托管”WndProc(以实现自定义下拉按钮)和“非托管”Win32 SetWindowSubclass / RemoveWindowSubclass(以实现下拉列表的鼠标事件)。最终效果是,该控件现在允许宿主程序使用托管代码完成许多原本需要对组合框使用非托管 API 才能完成的操作!(所有“非托管”内容都在幕后。)我鼓励任何想学习任何类型子类化以扩展控件功能的人研究源代码!
  5. 我在演示程序中包含了一个过程来支持显示 ExtComboBox 下拉列表项的工具提示,如下所示(已更新至 2022 年 9 月 13 日!)。
    Public Sub ShowExtComboBoxTooltip(ecb As ExtComboBox, tltp As ToolTip, _
        ByVal Text As String, _
        Optional ByVal X As Integer = -1, Optional ByVal Y As Integer = -1, _
        Optional ByVal AreForcingRedraw As Boolean = False)
    Const TooltipDuration As Integer = 5000
    Static OldXPos As Integer = 0, OldYPos As Integer = 0, _
        Index As Integer = -1
    Dim NewXPos, NewYPos As Integer
    '   hide tooltip if text is blank   
    If String.IsNullOrWhiteSpace(Text) Then
        tltp.Hide(ecb) : Exit Sub
    End If
    '   get current hover position
    Dim Rect As Rectangle, XOffset, YOffset As Integer
    If ecb.DroppedDown Then
        '   display tooltip over drop-down list item
        Rect = ecb.DropDownRectangle
        XOffset = Rect.X : YOffset = ecb.Height + Rect.Y
     Else
        '   display tooltip over edit portion
        Rect = ecb.ClientRectangle
        XOffset = Rect.X : YOffset = Rect.Y
    End If
    If X > -1 Then
        NewXPos = X + XOffset
     Else
        NewXPos = OldXPos 'default
    End If
    If Y > -1 Then
        NewYPos = Y + YOffset
     Else
        NewYPos = OldYPos 'default
    End If
    '   display tooltip only if selected index or mouse position is changed
    If ecb.SelectedIndex <> Index Then
        Index = ecb.SelectedIndex
     ElseIf NewXPos = OldXPos AndAlso NewYPos = OldYPos _
            AndAlso Not AreForcingRedraw Then
        Exit Sub 'index and position unchanged--allow to fade
     Else
        Index = ecb.IndexFromDropDownPoint(NewXPos, NewYPos)
    End If
    '   show tooltip if mouse position is in window
    tltp.Hide(ecb)
    If Rect.Contains(NewXPos, NewYPos) OrElse Index > -1 Then
        tltp.Show(Text, ecb, NewXPos, NewYPos + 3 + ecb.Cursor.Size.Height \ 2, _
            TooltipDuration)
    End If
    '   update position info
    OldXPos = NewXPos : OldYPos = NewYPos
    End Sub
© . All rights reserved.