ComboBox DroppedDown property bug. If set in constructor, WndProc messages are missing



I believe I have found a bug in the System.Windows.Forms.ComboBox
object. Quick background, there is a ComboBox event for when the drop
down list is shown, but not one when it is closed. This is because the
ComboBox does not receive any messages when it's drop down list is
being closed. It's parent is what receives the CBN_CLOSEUP event
notification (from the WM_COMMAND message). I wanted to know when a
ComboBox was closing its drop down list so I created a UserControl with
one ComboBox in it. I then overrode the UserControl's WndProc, looked
for WM_COMMAND message and so on.
Now for the bug...
When I use this UserControl on a form, all worked fine. But to get the
UserControl to act more like a ComboBox, I have to expose all the
ComboBox properties by declaring them through the UserControl as
properties. The first one I did was the DroppedDown property. Here is
where the bug comes in. In the constructor (New subroutine) of the
MainForm for the windows app, set the DroppedDown property of the
UserControl to False. Now when you run the app the WM_COMMAND message
is never sent to the UserControl. Uncomment out the DroppedDown = False
in the Main Form constructor and the WM_COMMAND messages are now
getting sent again. The steps to reproduce are below. I am not sure
what is all effects, but I am running VS 2003. I believe it occurs in
both C# and VB.NET along with Debug and Release mode.

Steps to reproduce...
-Open VS and create a new VB Windows Application (named MyTestApp)
-Once it is open, right click on the project in the Solution Explorer,
and select Add User Control (named UserControl1)
-In the user control, add one combo box (named ComboBox1)
-In the code for the user control, override the WndProc function (copy
and paste) (Note that &H111 is WM_COMMAND)
Protected Overrides Sub WndProc(ByRef msg As Message)
If (msg.Msg = &H111) Then
Dim x As String = ""
End If
End Sub
-Also in the code for the user control, expose the ComboBox's
DroppedDown property (copy and paste) (Make sure to include the
DefaultValue property)
<System.ComponentModel.DefaultValue(False)> _
Public Property DroppedDown() As Boolean
Return ComboBox1.DroppedDown
End Get
Set(ByVal Value As Boolean)
ComboBox1.DroppedDown = Value
End Set
End Property
-You are done with the UserControl, now go to the designer for the Main
Form (Form1)
-Drag a ComboBox from the "Windows Forms" tab in the toolbox anywhere
on the form
-Go in the code for the Main Form and change the two occurances of
"System.Windows.Forms.ComboBox" to "MyTestApp.UserControl1"
-In the UserControl code, put a breakpoint on the Dim x As String = ""
line and press F5 to run the application.
-You should see the breakpoint hit before the app even fully loads
because the UserControl will have focus, which CBN_SETFOCUS is on of
the WM_COMMANDs that is sent
-Once you verify that the breakpoint is hit, press Shift+F5 to stop
-Now go into the Main Form's code and find the New() sub (it will be in
the "Windows Form Designer generated code" region)
-Right after the InitializeComponent() call, set the DroppedDown
property of the UserControl to false (copy and paste)
ComboBox1.DroppedDown = False
-Make sure your breakpoint is still set on the same line and press F5
to run the app again.
This time you will notice that by setting the DroppedDown property in
the constructor, the UserControl now does not receive any WM_COMMAND
messages. Comment out the line and you will see that once again it
receives the messages.

I cant figure out why this is. It seems to be a bug, but I would
imagine it does not come up that often. Here is a similar topic I found
but I am not sure if it is the same behavior. It references a HotFix
from Microsoft but that does not sound like the same behavior I am



Claes Bergefall

Yes, something weird is going on. I can reproduce the problem.
BTW, it doesn't matter if you have a UserControl or not. You'll
get the same thing if you place a combobox directly on the form.

As for your original problem (getting the CBN_CLOSEUP
notification) there is an easier way of doing that, that doesn't
require a UserControl. All WM_COMMAND,
WM_NOTIFY and WM_DRAWITEM messages that are
sent to the parent are reflected by the framework to the control
itself. It does this by adding OCM__BASE to the message and
the resending the whole thing to the control.

So instead of putting a combobox on a usercontrol, simply
inherit the combobox and override it's WndProc. Here's the code:

Public Class ComboBoxEx
Inherits ComboBox
Private Const WM_USER As Integer = &H400
Private Const WM_COMMAND As Integer = &H111
Private Const OCM__BASE As Integer = WM_USER + &H1C00
Private Const OCM_COMMAND As Integer = OCM__BASE + WM_COMMAND

Private Function HIWORD(ByVal value As Integer) As Short
Return CShort(New System.Drawing.Point(value).Y)
End Function

Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
If m.Msg = OCM_COMMAND Then
Dim code As Integer = HIWORD(m.WParam.ToInt32)
If code = CBN_CLOSEUP Then
End If
End If
End Sub

Protected Overridable Sub OnCloseUp(ByVal e As System.EventArgs)
RaiseEvent CloseUp(Me, e)
End Sub

Public Event CloseUp As EventHandler
End Class


Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question