15

Ehm, umm, this means some lines should be two-lined in size. My boss think this is more simple solution, than limit displayed text to fit width and don't like horizontal scroll bar >_<

Sundara Prabu
  • 2,361
  • 1
  • 21
  • 20
Kosmo零
  • 4,001
  • 9
  • 45
  • 88

4 Answers4

39
lst.DrawMode = System.Windows.Forms.DrawMode.OwnerDrawVariable;
lst.MeasureItem += lst_MeasureItem;
lst.DrawItem += lst_DrawItem;

private void lst_MeasureItem(object sender, MeasureItemEventArgs e)
{
    e.ItemHeight = (int)e.Graphics.MeasureString(lst.Items[e.Index].ToString(), lst.Font, lst.Width).Height;
}

private void lst_DrawItem(object sender, DrawItemEventArgs e)
{
    e.DrawBackground();
    e.DrawFocusRectangle();
    e.Graphics.DrawString(lst.Items[e.Index].ToString(), e.Font, new SolidBrush(e.ForeColor), e.Bounds);
}
Kosmo零
  • 4,001
  • 9
  • 45
  • 88
  • Love it. One minor thing though. When I databind a custom class, the DisplayMember gets wiped and I can't seem to reset it. Any tips? – Bill Sambrone Mar 25 '14 at 23:58
  • @BillSambrone - Sorry, but I don't use databind and never meet same problem and don't know how to solve. – Kosmo零 Mar 27 '14 at 20:03
  • @AycanYaşıt : totaly agree – Sebastien H. Aug 27 '14 at 10:44
  • @Kosmos Seems that the `ListBox` caches the items height, what is good. The problem is that if the `ListBox` is resized it don't recalculates the height! I'm trying someway to clean the cache of items height without removing and adding then, in the `resize`, but I don't find any method for that. At least documented. – Diego C Nascimento Feb 12 '15 at 15:13
  • @DiegoCNascimento - I used `ListBox.Refresh` method in `resize` handler for that. – Kosmo零 Feb 12 '15 at 19:41
  • @Kosmos `Refresh` does not work, it will just add all the area of the `ListBox` to next `Paint` event, but does not calculate the new items height. – Diego C Nascimento Feb 13 '15 at 00:39
  • @DiegoCNascimento - I don't know why, but for me it worked fine. I used Form's resize event and called list box's Refresh method. I don't know why you telling it's not working. Refresh causes control to redraw and when it redraws it should run the calculation code again. – Kosmo零 Feb 13 '15 at 16:32
  • @Kosmos what version of .Net are you using (even trough the `ListBox` is a native windows control)? It don't raise the `MeasureItem` event, you can search for the same question in other places. Anyway I found [a way to change item height](http://stackoverflow.com/questions/28490543/windows-forms-listbox-with-ownerdrawvariable-bug) – Diego C Nascimento Feb 15 '15 at 15:43
  • Also take a look at that **Unfortunately, the MeasureItem event only happens when the handle gets created** in [this answer](http://stackoverflow.com/questions/7072539/expanding-selected-item-height-in-listbox/7072554). – Diego C Nascimento Feb 15 '15 at 15:50
  • @DiegoCNascimento - Meh, I tested it and finally understand what you meant. I though that text stays the same after resizing (no updates), but the text changes according to space available, while item height no. Well..., currently I don't know what to do. – Kosmo零 Feb 15 '15 at 21:54
  • @Kosmos Yes, that's it. Putting it, the item height is dependent on the item width, being the item width dependent on the control client area width. I come [with a solution](http://stackoverflow.com/questions/28490543/windows-forms-listbox-with-ownerdrawvariable-bug). The `ListBox` that is a native windows control, has way to set item height, so you can call it with "Windows API". Also, I make a call to the measure item, for each item and called the "Windows API", so that it worked. There's only a glitch when the scroll bar gets show or hidden. Thanks! – Diego C Nascimento Feb 17 '15 at 17:32
  • @BillSambrone If you use a custom class, you need to replace "lst.Items[e.Index].ToString()" to "((CustomClass)lst.Items[e.Index]).YourMethodShowTheClass". – dlopezgonzalez Jul 31 '15 at 10:00
  • Worked like a charm. – Zhong Ri Mar 12 '19 at 08:39
2
private void lst_MeasureItem(object sender, MeasureItemEventArgs e)
{
    e.ItemHeight = (int)e.Graphics.MeasureString(lst.Items[e.Index].ToString(), lst.Font, lst.Width).Height;
}

private void lst_DrawItem(object sender, DrawItemEventArgs e)
{
    e.DrawBackground();
    e.DrawFocusRectangle();
    e.Graphics.DrawString(lst.Items[e.Index].ToString(), e.Font, new SolidBrush(e.ForeColor), e.Bounds);
}

To get the right display member to show up when data binding, replace

lst.Items[e.Index].ToString()

with a casted version of the property. So if your binding source is class object Car it would look like

((Car)lst.Items[e.Index]).YourDisplayProperty

Then the above functions can appropriately measure the string and draw it. :)

0

Helpful link

Check out this answer. It overrides the template of the listbox with a textblock which wraps the text. Hope it's useful. To solve your problem I think you shold add : ScrollViewer.HorizontalScrollBarVisibility="Disabled" . Found it here

Community
  • 1
  • 1
Andrei Neculai
  • 472
  • 2
  • 5
  • 21
0

To make binding correct, be sure to add check "lst.Items.Count > 0" to lst_MeasureItem function. Here is my example:

 if (lst.Items.Count > 0)
 {
    e.ItemHeight = (int)e.Graphics.MeasureString(lst.Items[e.Index].ToString(), lst.Font, lst.Width).Height;
 }

Everything else seems to work nicely after that.