Hello,
If I place a standard .NET combobox on a Windows Form, I can write code such
that items are added to the list while the combobox's dropdown is displayed.
The following sample code uses a timer to accomplish this (I added a combobox
named comboBox1 to the form):
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
//populate combobox with some initial items
for (int i = 0; i < 10; i++)
comboBox1.Items.Add(i);
_addItemsTimer = new Timer();
_addItemsTimer.Interval = 3000;
_addItemsTimer.Tick += new EventHandler(_addItemsTimer_Tick);
}
void _addItemsTimer_Tick(object sender, EventArgs e)
{ //add a bunch more items to the dropdown
for (int i = 15; i < 55; i++)
comboBox1.Items.Add(i + offSet);
offSet = offSet + 50;
}
private void comboBox1_DropDown(object sender, EventArgs e)
{
//start timer that will add items to dropdown list
_addItemsTimer.Start();
}
private void comboBox1_DropDownClosed(object sender, EventArgs e)
{
_addItemsTimer.Stop();
}
private Timer _addItemsTimer;
private int offSet;
}
If I click the dropdown icon on the combobox, the initial list of items is
displayed. After waiting three seconds, more items are added. Here's the
problem: when the new items are added, the size of the dropdown window
greatly increases (the first time items are added). This is rather ugly.
Worse, if the form happens to be near the bottom of the screen, then if the
dropdown is expanded and items are added, the dropdown list window extends
beyond the desktop size. The user cannot scroll down to see additional
items. When the dropdown is closed and reopened, the dropdown window height
returns to normal. How can I avoid the dropdown size (height) changing while
still adding items to the list when the dropdown is displayed?
Thanks,
Notre
AlBruAn - 14 Dec 2006 07:05 GMT
Are you required to display the items as they're being added to the combobox?
If not, you might consider executing comboBox1.BeginUpdate prior to adding
the items to the combobox and then executing comboBox1.EndUpdate after you've
added the items. You won't see the items as they are being added and you may
not see them after they've been added, but this last matter could be overcome
by executing comboBox1.Refresh.
> Hello,
>
[quoted text clipped - 55 lines]
> Thanks,
> Notre
Linda Liu [MSFT] - 14 Dec 2006 08:54 GMT
Hi Notre,
I performed a test based on your sample code and did see the same thing as
you did.
When the items of a ComboBox are changed while the drop down list is
visible, the ComboBox receives WM_CTLCOLORLISTBOX message to draw the drop
down list and then the height of the drop down list increases.
In order to keep the height of the drop down list unchanged, we could
override the WndProc method of the ComboBox and catch the
WM_CTLCOLORLISTBOX message and then set the height of the drop down list to
the original value.
The following is the sample code.
class MyComboBox:ComboBox
{
private int dropdownHeight = 0;
public MyComboBox()
{
// write down the original value of the DropDownHeight property
dropdownHeight = this.DropDownHeight;
}
private const int WM_CTLCOLORLISTBOX = 0x0134;
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_CTLCOLORLISTBOX)
{
// keep the value of the DropDownHeight property unchanged
this.DropDownHeight = this.dropdownHeight;
}
base.WndProc(ref m);
}
}
Build the project and use the derived ComboBox on your form instead of the
standard ComboBox.
I have tested the above code and confirmed it works.
If you have anything unclear, please feel free to let me know.
Sincerely,
Linda Liu
Microsoft Online Community Support
==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications.
Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/subscriptions/support/default.aspx.
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
Notre Poubelle - 15 Dec 2006 00:54 GMT
Hi Linda,
Thanks very much! This works pretty well. There are a couple of little
problems I noticed.
First, the first time the user tries to expand the dropdown by clicking the
dropdown on the combobox, the combobox immediately collapses the combobox
dropdown list. (This happens only the first time).
Second, when the dropdown is collapsed, it also does one other nasty thing:
the window handle to the dropdown portion of the combobox is invalidated.
I'm capturing the dropdown window handle in the MyComboBox constructor by
means of the unmanaged GetComboBoxInfo API (the hwndList member of
COMBOBOXINFO structure contains this window handle). After the dropdown list
disappears, if I try to put the window handle in Spy++, there's an error
message saying that window handle is no longer valid.
Third, and I think this is related to the second problem, is that the first
time the drop down collapses, if I have a DropDownClosed event handler, it
does not fire when the dropdown closes unexpectedly. (Subsequent open/close
of the drop down does fire the DropDownClosed event).
So, I have two related questions.
1. How to stop the dropdown from immediately closing, the first time the
user clicks the dropdown arrow.
2. How to avoid invalidating the window handle.
The answer to number 1 is more important than the answer to number 2, as I
could reget the (new) dropdown handle by calling GetComboBoxInfo again.
Thanks!
Notre
Notre Poubelle - 15 Dec 2006 06:02 GMT
Hi Linda,
I found a workaround to the dropdown immediately closing after its first
open. I modified the constructor code to set the DropDownHeight property
immediately after getting it. i.e.
public MyComboBox()
{
dropdownHeight = this.DropDownHeight;
this.DropDownHeight = dropdownHeight;
//other initialization follows, including get the combobox info via
GetComboBoxInfo
}
This does seem to invalidate the dropdown window handle (the act of setting
the DropDownHeight the first time in the constructor), but the end user
doesn't see anything happen.
Does this seem like a reasonable workaround? Any problems that you could
forsee with this workaround?
Thanks,
Notre
Linda Liu [MSFT] - 15 Dec 2006 07:55 GMT
Hi Notre,
Thank you for your detailed feedback.
I do see the problem of my workaroud. I am sorry that I didn't noticed this
problem before.
It seems that it is not a good solution to catch the WM_CTLCOLORLISTBOX
message. Fortunately, we have another option. That is to catch CB_ADDSTRING
message. This message is sent by the application to add a string to the
list box of the combo box.
The following is a sample for you.
class MyComboBox:ComboBox
{
private int dropdownHeight = 0;
public MyComboBox()
{
// write down the original value of the DropDownHeight property
dropdownHeight = this.DropDownHeight;
}
private const int CB_ADDSTRING = 0x0143;
protected override void WndProc(ref Message m)
{
if (m.Msg == CB_ADDSTRING)
{
// keep the value of the DropDownHeight property unchanged
this.DropDownHeight = this.dropdownHeight;
}
base.WndProc(ref m);
}
}
Please try my suggestion and let me know the result.
Sincerely,
Linda Liu
Microsoft Online Community Support