Ste*_*bob 5 .net vb.net wpf visual-studio-2008 winforms
我无法正确设置ComboBox的DropDownHeight以显示所有项目.
我正在使用从ComboBox继承的控件.我已经重写了OnDrawItem和OnMeasureItem方法,以便在需要时在列中创建多个列和文本换行.一切正常.
当我尝试设置DropDownHeight时会出现问题.我将DropDownHeight设置为一个任意大的值,比项目列表大一点.ComboBox控件似乎自动截断DropDownHeight的任何值,该值大于列表中所有显示项的大小.(假设您将MaxDropDownItems属性设置为高于项目数,我这样做.)通常这种行为完美无缺,如下所示: alt text http://www.freeimagehosting.net/uploads/dd09404697.png
不,这不是我在下拉框中的真实数据.
当我在下拉列表中有一个条目需要换行以显示全文时,会出现问题.此条目显示正常,但是ComboBox正在计算DropDownHeight,它忽略了其中一个条目是正常值的两倍这一事实,因此您必须向下滚动一行才能到达下拉列表中的最后一个条目. alt text http://www.freeimagehosting.net/uploads/d0ef715f83.png
这是我用来确定项目是否需要文本换行以及设置每个项目的高度的代码:
Protected Overrides Sub OnMeasureItem(ByVal e As System.Windows.Forms.MeasureItemEventArgs)
MyBase.OnMeasureItem(e)
//Determine the proper height of the current row in the dropdown based on
//the length of the OptionDescription string.
Dim tmpStr As String = FilterItemOnProperty(Items(e.Index), "OptionDescription")
Dim lng As Single = e.Graphics.MeasureString(tmpStr, Me.Font).Width
//Use the length of the item and the width of the column to calculate if wrapping is needed.
Dim HeightMultiplier As Integer = Math.Floor(lng / _ColumnWidths(1)) + 1
e.ItemHeight = e.ItemHeight * HeightMultiplier
End Sub
Run Code Online (Sandbox Code Playgroud)
我无法确定如何强制DropDownHeight属性正好是我想要的值,或者如何让ComboBox控件知道列表中的一个(或多个)项目高于正常值.
我试图覆盖 Shadow DropDownHeight属性,但这似乎没有任何影响.
编辑:
切换到WPF会让这个问题消失吗?(标准WPF控件中是否有足够的可自定义性,因此我不需要为3列可变高度组合框编写自定义控件?)
小智 9
我正试图解决这个完全相同的问题,目前我正在从VB6迁移到VB.NET的应用程序.我在VB6中拥有的所有者绘制的组合控件通过SetWindowPos API调用设置下拉的高度,以响应组合控件上的WM_CTLCOLORLISTBOX消息,这使我们可以访问组合下拉列表的HWnd控制.以下代码被添加到我的类中,它继承自ComboBox,似乎可以解决这个问题,但仍需要测试.我不确定这也是最优雅的方式.显然你需要更改设置newHeight变量的行,但这应该给你一般的想法.
Private Structure RECT
Public Left As Integer 'x position Of upper-left corner
Public Top As Integer 'y position Of upper-left corner
Public Right As Integer 'x position Of lower-right corner
Public Bottom As Integer 'y position Of lower-right corner
End Structure
Private Declare Function GetWindowRect Lib "user32" _
(ByVal hwnd As Integer, ByRef lpRect As RECT) As Integer
Private Declare Sub SetWindowPos Lib "user32" _
(ByVal hwnd As Integer, ByVal hWndInsertAfter As Integer, _
ByVal X As Integer, ByVal Y As Integer, _
ByVal cx As Integer, ByVal cy As Integer, _
ByVal wFlags As Integer)
Private Const SWP_NOZORDER As Integer = &H4
Private Const SWP_NOACTIVATE As Integer = &H10
Private Const SWP_FRAMECHANGED As Integer = &H20
Private Const SWP_NOOWNERZORDER As Integer = &H200
Private _hwndDropDown As Integer = 0
Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
Const WM_CTLCOLORLISTBOX As Integer = &H134
If m.Msg = WM_CTLCOLORLISTBOX Then
If _hwndDropDown = 0 Then
_hwndDropDown = m.LParam.ToInt32
Dim r As RECT
GetWindowRect(m.LParam.ToInt32, r)
'height of four items plus 2 pixels for the border in my test
Dim newHeight As Integer = 4 * MyBase.ItemHeight + 2
SetWindowPos(m.LParam.ToInt32, 0, _
r.Left, _
r.Top, _
MyBase.DropDownWidth, _
newHeight, _
SWP_FRAMECHANGED Or _
SWP_NOACTIVATE Or _
SWP_NOZORDER Or _
SWP_NOOWNERZORDER)
End If
End If
MyBase.WndProc(m)
End Sub
Protected Overrides Sub OnDropDownClosed(ByVal e As System.EventArgs)
_hwndDropDown = 0
MyBase.OnDropDownClosed(e)
End Sub
Run Code Online (Sandbox Code Playgroud)