Winforms 等同于Microsoft Forms 2.0 ComboBox。Windows窗体和Access窗体中的TopIndex属性?
不推荐使用的Microsoft Forms 2.0控件包含一个组合框,该组合框提供了一个非常宝贵的属性:.TopIndex 根据文档,此属性似乎不适用于Microsoft Access 2019中表单中的标准组合框,也不适用于Windows forms.NET中的标准组合框。此处,组合框继承自ListControl,不提供此属性,而ListBox也继承自ListControl,但是它提供了它 我有很多严重依赖.TopIndex属性的旧代码,现在是将这些代码转移到其他技术的时候了 所以我想知道我是否遗漏了文档中的某些内容,以及是否有一个具有另一个名称的等效属性,我可以使用它来确定组合框的列表部分中哪些项是可见的。我想知道Access 2019中的组合框的情况,我对这个应用程序并不像这里的许多其他应用程序以及Windows窗体中的组合框那样充满敌意 我知道有很多免费和商业控件,包括具有Windows窗体增强功能的组合框。除非我在文档中遗漏了什么,否则我肯定会这样做,或者自己写Winforms 等同于Microsoft Forms 2.0 ComboBox。Windows窗体和Access窗体中的TopIndex属性?,winforms,ms-access,combobox,ms-access-forms,ms-forms,Winforms,Ms Access,Combobox,Ms Access Forms,Ms Forms,不推荐使用的Microsoft Forms 2.0控件包含一个组合框,该组合框提供了一个非常宝贵的属性:.TopIndex 根据文档,此属性似乎不适用于Microsoft Access 2019中表单中的标准组合框,也不适用于Windows forms.NET中的标准组合框。此处,组合框继承自ListControl,不提供此属性,而ListBox也继承自ListControl,但是它提供了它 我有很多严重依赖.TopIndex属性的旧代码,现在是将这些代码转移到其他技术的时候了 所以我想知道我是
然而,在访问2019个表单时,情况完全不同。我找不到一个可以在Access窗体上使用并提供此功能的免费第三方ActiveX/COM组合框。理论上,我可能可以使用.NET编写ActiveX/COM控件,然后在Access表单上使用它,但这似乎很痛苦。就.NET WinForm ComboBox而言,您没有错过任何东西,因为TopIndex属性的功能没有实现。也就是说,扩展基本ComboBox控件以添加此属性是非常简单的。下面的示例控件应该可以帮助您开始 此控件将侦听器附加到本机ListBox下拉列表,并更新WM_VSCROLL上的TopIndex属性,从而捕获打开消息的初始位置。此外,基本SelectedIndexChange事件用于捕获由于键盘操作pgUp/pgDn、向上/向下箭头引起的更改。TopIndex属性在下拉列表关闭后保留,并在打开下拉列表时重置。该控件还公开TopIndexChanged事件
Imports System.Runtime.InteropServices
Public Class ComboBoxEx : Inherits ComboBox
Private listBoxListener As ListBoxNativeWindow
Public Event TopIndexChanged As EventHandler(Of ComboBoxTopIndexArg)
Private _TopIndex As Int32 = -1
Public Sub New()
MyBase.New
listBoxListener = New ListBoxNativeWindow(Me)
End Sub
Public Property TopIndex As Int32
Get
Return _TopIndex
End Get
Private Set(value As Int32)
If value <> _TopIndex Then
_TopIndex = value
RaiseEvent TopIndexChanged(Me, New ComboBoxTopIndexArg(value))
End If
End Set
End Property
Protected Overrides Sub OnDropDown(e As EventArgs)
_TopIndex = -1 ' reset on opening the listbox
MyBase.OnDropDown(e)
End Sub
Private Class ListBoxNativeWindow : Inherits NativeWindow
Private listBoxHandle As IntPtr
Private TopIndex As Int32
Private parent As ComboBoxEx
Public Sub New(ByVal parent As ComboBoxEx)
Me.parent = parent
WireParent()
If parent.IsHandleCreated Then
GetListBoxHandle()
AssignHandle(listBoxHandle)
End If
End Sub
Private Sub WireParent()
AddHandler parent.HandleCreated, AddressOf Me.OnHandleCreated
AddHandler parent.HandleDestroyed, AddressOf Me.OnHandleDestroyed
AddHandler parent.SelectedIndexChanged, AddressOf UpdateTopIndexOnIndexChanged
End Sub
Private Sub OnHandleCreated(ByVal sender As Object, ByVal e As EventArgs)
GetListBoxHandle()
AssignHandle(listBoxHandle)
End Sub
Private Sub OnHandleDestroyed(ByVal sender As Object, ByVal e As EventArgs)
ReleaseHandle()
End Sub
Private Sub UpdateTopIndexOnIndexChanged(sender As Object, e As EventArgs)
SetParentTopIndex()
End Sub
Private Sub GetListBoxHandle()
Const CB_GETCOMBOBOXINFO As Int32 = &H164
Dim info As New ComboBoxInfo
info.cbSize = Marshal.SizeOf(info)
Dim res As Boolean = SendMessage(Me.parent.Handle, CB_GETCOMBOBOXINFO, Nothing, info)
listBoxHandle = info.hwndList
End Sub
Protected Overrides Sub WndProc(ByRef m As Message)
Const WM_VSCROLL As Int32 = &H115
Const LB_SETCARETINDEX As Int32 = &H19E
MyBase.WndProc(m)
If m.Msg = WM_VSCROLL OrElse m.Msg = LB_SETCARETINDEX Then
SetParentTopIndex()
End If
End Sub
Private Sub SetParentTopIndex()
Const LB_GETTOPINDEX As Int32 = &H18E
parent.TopIndex = SendMessage(listBoxHandle, LB_GETTOPINDEX, IntPtr.Zero, IntPtr.Zero)
End Sub
End Class
Public Class ComboBoxTopIndexArg : Inherits EventArgs
Public Sub New(topIndex As Int32)
Me.TopIndex = topIndex
End Sub
Public ReadOnly Property TopIndex As Int32
End Class
#Region "NativeMethods"
<StructLayout(LayoutKind.Sequential)>
Private Structure ComboBoxInfo
Public cbSize As Int32
Public rcItem As RECT
Public rcButton As RECT
Public stateButton As IntPtr
Public hwndCombo As IntPtr
Public hwndEdit As IntPtr
Public hwndList As IntPtr
End Structure
<StructLayout(LayoutKind.Sequential)>
Private Structure RECT
Public Left, Top, Right, Bottom As Int32
End Structure
<DllImport("user32.dll")>
Private Shared Function SendMessage(hWnd As IntPtr, Msg As Int32, wParam As IntPtr, <Out()> ByRef lParam As ComboBoxInfo) As Boolean
End Function
<DllImport("user32.dll")>
Private Shared Function SendMessage(hWnd As IntPtr, Msg As Int32, wParam As IntPtr, lParam As IntPtr) As Int32
End Function
#End Region
End Class
我让您将其包装在ActiveX公开包装中,以便在Access中使用。使用中的模板执行此操作相当容易。请注意,这些模板是使用Any CPU平台设置的,您需要将其更改为x86。我不确定TopIndex在组合框中的用途,您可能只需要选择的索引。如果您想显示一个特定的项目>MaxDropDownItems,设置comboBox1.SelectedIndex=N,我认为您可以使用类似的功能;comboBox1.DroppedDown=true;在列表框中,TopIndex LB_GETTOPINDEX、LB_SETTOPINDEX用于在重新创建LB句柄时重新创建以前的布局。在组合框中,它的dropcrowd总是新的。事实证明,这个属性对于实现带有分页的组合框非常有用。我有一个应用程序,其中大约有40万个可能的条目可以加载到combobox中,当然这在性能和可用性方面没有任何意义。因此,我从50个条目开始,根据需要加载其余条目。这里的问题是,用户可以使用鼠标滚轮以及PgUp、PgDown、Cursor等滚动combobox下拉列表。您可以使用LINQ或DataTable过滤combobox.DataSource。DefaultView filters+LINQ,最终这些技术不是用于客户端过滤吗?当然,我不想从数据库中提取所有可能的记录,然后在客户端对它们进行过滤。此外,我无法想象过滤器在这里能起到什么作用。我的问题是根据用户的滚动来确定我应该在组合框的列表部分获取/显示哪部分数据。哇,非常感谢。我认为这个答案没有什么可补充的——绝对是个好工作!几行代码显示了如何捕获任何事件,再加上对一个有价值的工具包的引用,直到现在我才知道这个工具包只使用了.NET几次,而且只有一次我在没有工具箱帮助的情况下将.NET代码放入ActiveX中。如果可以的话,我会投上一百次。