I have a ListBox in WinForms that displays some data, and when you click on an item, it expands and displays more. This is the code:
private void historyList_SelectedIndexChanged(object sender, EventArgs e)
{
historyList.Refresh();
}
private void historyList_DrawItem(object sender, DrawItemEventArgs e)
{
e.DrawBackground();
FeedHistoryItem item = (sender as ListBox).Items[e.Index] as FeedHistoryItem;
if (e.Index == historyList.SelectedIndex)
{
e.Graphics.DrawString(item.ExpandedText,
e.Font, Brushes.Black, e.Bounds);
}
else
{
e.Graphics.DrawString(item.CollapsedText,
e.Font, Brushes.Black, e.Bounds);
}
e.DrawFocusRectangle();
}
private void historyList_MeasureItem(object sender, MeasureItemEventArgs e)
{
FeedHistoryItem item = (sender as ListBox).Items[e.Index] as FeedHistoryItem;
string itemText = e.Index == historyList.SelectedIndex ? item.ExpandedText : item.CollapsedText;
int size = 15 * (itemText.Count(s => s == '\r') + 1);
e.ItemHeight = size;
}
The events are called as expected. When you click on an item, it calls Refresh(), then measure, then draw. The text expands. However, the size doesn't change.
I've verified that the first time an item is drawn, it respects when I put in ItemHeight, but when resizing, it does not - if I set a breakpoint in the DrawItem method, even though MeasureItem was just called, the height in e.Bounds does not update. Yes - I do have historyList.DrawMode = DrawMode.OwnerDrawVariable; set.
Any ideas?
I required something similar: when the
ListBox
is resized I need the items to resize too to fit the new width.So every time my ListBox is resized I call the following method, which will resize every item! (be carefully when you have too much items)
Usage:
Reference: MSDN Community
Try inheriting the ListBox control and call the RecreateHandle on the OnSelectedIndexChanged method.
Unfortunately, it will probably flicker, but I think it's the only way to get the ListBox to call the MeasureItem event again. The other way is to suspend the drawing and then remove the item from the list and put it back in again. No clean way to do this in WinForms.