重新测量ListBox中的现有项目

时间:2013-12-13 16:16:42

标签: c# .net winforms listbox

我在WinForms中有一个显示一些数据的ListBox,当你点击一个项目时,它会展开并显示更多数据。这是代码:

  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;
  }

事件按预期调用。当您单击某个项目时,它会调用Refresh(),然后测量,然后绘制。文字扩大了。但是,尺寸不会改变。

我已经验证了第一次绘制项目时,它会在我放入ItemHeight时受到尊重,但是在调整大小时,它不会 - 如果我在DrawItem方法中设置断点,即使刚刚调用了MeasureItem, e.Bounds中的高度不会更新。是的 - 我确实有historyList.DrawMode = DrawMode.OwnerDrawVariable;集。

有什么想法吗?

2 个答案:

答案 0 :(得分:2)

尝试继承ListBox控件并在OnSelectedIndexChanged方法上调用RecreateHandle。

public class ListEx : ListBox {
  protected override void OnSelectedIndexChanged(EventArgs e) {
    base.OnSelectedIndexChanged(e);
    this.RecreateHandle();
  }
}

不幸的是,它可能会闪烁,但我认为这是让ListBox再次调用MeasureItem事件的唯一方法。另一种方法是暂停绘图,然后从列表中删除该项目并再次将其重新放入。在WinForms中没有干净的方法。

答案 1 :(得分:0)

我需要类似的内容:调整ListBox的大小时,我也需要调整项目的大小以适应新的宽度。

因此,每次调整ListBox的大小时,我都会调用以下方法,该方法将调整每个项目的大小! (当您有太多物品时要小心)

private static void ForceMeasureItems(ListBox listBox, Action<object, MeasureItemEventArgs> onMeasureEvent)
{
    for (int i = 0; i < listBox.Items.Count; i++)
    {
        MeasureItemEventArgs eArgs = new MeasureItemEventArgs(listBox.CreateGraphics(), i);
        onMeasureEvent(listBox, eArgs);
        SendMessage(listBox.Handle, LB_SETITEMHEIGHT, i, eArgs.ItemHeight);
    }
    listBox.Refresh();
}

用法:

private void OnMyMeasureItem(object sender, MeasureItemEventArgs e)
{
    // measure logic goes here
    int myCustomHeightValue = 22;
    e.ItemHeight = myCustomHeightValue;
}

ListBox listBox = new ListBox();
listBox.MeasureItem += OnMyMeasureItem;
listBox.Resize += (sender, args) => ForceMeasureItems(listBox, OnMyMeasureItem);

参考:MSDN Community