开发者

How to make combobox remeasure item height?

I am creating a custom combobox whi开发者_开发百科ch 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)?


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


You can call ComboBox.RefreshItems() in order to raise MeasureItem() calls, either inside your SpecifySeparatorItem() of your CustomCombo class :

public void SpecifySeparatorItem(object arg)
{
    //do some stuff

    this.RefreshItems();

    //do some more stuff
}

Or by exposing ComboBox.RefreshItems() through a public method that you can call elsewhere

public partial class CustomCombo : ComboBox
{
    public CustomCombo ()
    {
        InitializeComponent();
    }

    protected override void OnMeasureItem(MeasureItemEventArgs e)
    {
        base.OnMeasureItem(e);
    }

    public void RaiseOnMeasureItem()
    {
        this.RefreshItems();
    }
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜