C# – How to make combobox remeasure item height

ccustom-controlsnetwinforms

I am creating a custom combobox which can draw separators. So, I override OnDrawItem() and OnMeasureItem() methods.
The problem is that OnMeasureItem() is called only once when datasource is changed. So if I want to specify a separator item later I need to remeasure it's height (because items with separator should be taller), but it seems that all methods that can lead to item height being remeasured are private, so I can't call them.
I don't know if it's easy to understand what I've written above, so I will repeat what I need:
I need to remeasure item height (OnMeasureItem() must be called) each time when I specify that the item should be drawn with a separator.

separatorableComboBox.DataSource = customers;
// and now I want the third customer in the list to be drawn with a separator, 
// so it needs to be taller and therefore OnMeasureItem() should be called
separatorableComboBox.SpecifySeparatorItem(customers[2]);

UPD. Guys, calling RefreshItems() works, but it's very slow (> 20 ms on my machine), are there faster methods?
UPD2. Right now I am using SendMessage(…, CB_SETITEMHEIGHT, …); method as serge_gubenko advised. But I'm just curious if there is a fast way of accomplishing the task with .NET (or more specifically with ComboBox class itself)?

Best Answer

Just to clarify, I assume you're using OwnerDrawVariable style for your combobox. If I understood your question correctly, there are couple of ways to do what you need:

  • Call RefreshItems method of the combobox which would recreate items and trigger onMeasureItem event for each item. This method is protected for the ComboBox class, so below is an example on how you could do it using reflection:
    MethodInfo method = comboBox1.GetType().GetMethod(
        "RefreshItems", BindingFlags.Instance | BindingFlags.NonPublic);
    if (method != null) method.Invoke(comboBox1, null);
  • Send the CB_SETITEMHEIGHT message to the control with the new height of the item whenever you want to change it:
    public const int CB_SETITEMHEIGHT = 0x0153;
    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, int wParam, int lParam);
    ...
    // this will set height to 100 for the item with index 2 
    SendMessage(comboBox1.Handle, CB_SETITEMHEIGHT, 2, 100); 

Hope this helps, regards