Windows.Forms.ListBox with OwnerDrawVariable bug?

2019-02-15 20:56发布

问题:

In a Windows.Forms.ListBox with the property DrawMode set to OwnerDrawVariable, the ListBox seems to cache the height of the items, what is good.

BUT, being the item height dependent of the width, because it uses Graphics.MeasureString to do word wrap, needs to calculate the height of items if the size of the ListBox has changed. Then there's a problem.

The ListBox doesn't do this by default, and I can't find a method to clear the cache, forcing the ListBox to raise the itemheight event.

Any solution? I tried to get the source for the ListBox but don't find anything about that to make a derived class and clear this cache.

(Tried copying the items to an array, clearing the ListBox.Items, and tem adding the array again. This even throw exceptions as the ListBox calling the drawitem or itemheight events with invalid item index)

回答1:

According this MSDN

LB_SETITEMHEIGHT message

Sets the height, in pixels, of items in a list box. If the list box has the LBS_OWNERDRAWVARIABLE style, this message sets the height of the item specified by the wParam parameter. Otherwise, this message sets the height of all items in the list box.

So this will do it

private const int LB_SETITEMHEIGHT = 0x01A0;

[DllImport("user32.dll")]
public static extern int SendMessage(IntPtr hWnd, int wMsg, IntPtr wParam, IntPtr lParam);

private void ListBoxExample_Resize(object sender, EventArgs e)
{
    for (int i = 0; i < ListBoxExample.Items.Count; i++)
    {

        MeasureItemEventArgs eArgs = new MeasureItemEventArgs(null, i);
        ListBoxExample_MeasureItem((object)ListBoxExample, eArgs);
        SendMessage((IntPtr) ListBoxExample.Handle, LB_SETITEMHEIGHT, (IntPtr) i, (IntPtr) e.ItemHeight);
    }
}

The MeasureItemEventArgs accepts a Graphics object, if necessary, create one from the control and pass it in the first argument.