3

Hey all I have been looking around the ol' net for a soluction that would allow me to resize my listview depending on the last entry in it.

So far I have only turned out how to do this using other controls like Telerik and Syncfusion, etc... Besides those companies I only find ways to just size up the row or column depending on the content inside it - not the overall height of the listview itself. Other examples also are close to what I am looking to want to do but are for WPF.

My winform looks like this right now:

enter image description here

But what I am wanting it to do is this:

enter image description here

Has anyone done this before that could show the code they used? Or is there a better control I could be using for my needs that would do what I am needing? Thanks!

Jimi
  • 29,621
  • 8
  • 43
  • 61
StealthRT
  • 10,108
  • 40
  • 183
  • 342
  • If you don't need `ScrollViewer`, then just [remove it](https://stackoverflow.com/q/1739216/1997232) from `ListView` control template. – Sinatr May 20 '21 at 13:08
  • I possibly will need the scrollbars if the listview grows taller than the LCD screen height resolution. – StealthRT May 20 '21 at 13:15
  • You can put `ListView` inside `ScrollViewer` then. – Sinatr May 20 '21 at 13:53
  • If you want to resize the ListView Control itself, based on the overall content - if that's what you want to do - just call SendMessage to send [LVM_APPROXIMATEVIEWRECT](https://learn.microsoft.com/en-us/windows/win32/controls/lvm-approximateviewrect) to the Control. It will return the approximate Height in the HI-Word. This value includes the Header's height. – Jimi May 20 '21 at 14:58
  • @Jimi mind putting an example of this up? All I find is C++ code. – StealthRT May 20 '21 at 17:32
  • Well, sure. But, did I get your intentions correctly? Do you want to size the Control based on its content, so the Scrollbar(s) are hidden? I assume you do have to limit the extent of the Control, at some point at least. – Jimi May 20 '21 at 17:37
  • @Jimi yes that is correct. Whatever the last row is in the listview is where I am wanting to height of the listview to go to. – StealthRT May 20 '21 at 17:59

1 Answers1

2

Sending a LVM_APPROXIMATEVIEWRECT message to Control, you can get back an approximate measure that includes the Header's height and the size of all the Items.
Setting the ClientSize of the Control to this measure, should allow to resize the ListView, to show all Items in their full extent.

You can specify a number of Items to include (wParam) and a preferred size (lParam), or set both lParam and wParam to -1: in this case, all Items are included and the size is auto-detected.

Note that the height may include the horizontal Scrollbar height: a margin may be visible at the bottom.
If that's not desirable, remove SystemInformation.HorizontalScrollBarHeight from the overall height.

Or do the same thing to limit the extent of the Control to a specific measure, if the number of Items in the ListView suggests it.

► As noted in comments, if the ListView is docked to the Form, setting its ClientSize doesn't have any visible effect.
In this case, you need to also resize the Form, adding the difference between the old Size of the ListView and its new calculated size.

Assuming the ListView is named listView1:

Size oldSize = listView1.ClientSize;
int hScrollBarHeight = SystemInformation.HorizontalScrollBarHeight

// Both wParam and lParam set to -1: include all Items and full size
int approxSize = NativeMethods.SendMessage(
    listView1.Handle, NativeMethods.LVM_APPROXIMATEVIEWRECT, -1, (-1 << 16 | -1));
int approxHeight = approxSize >> 16;
int approxWidth = approxSize & 0xFFFF;

Size newSize = new Size(approxWidth, approxHeight - hScrollBarHeight);

// If needed, resize the Form (here, grow and shrink) to adapt to the new size
// Checking the Dock property state is a possible example, apply whatever logic fits
if (listView1.Dock != DockStyle.None) {
    this.Height += newSize.Height - oldSize.Height;
    this.Width += newSize.Width - oldSize.Width;
}

listView1.ClientSize = newSize;

internal class NativeMethods 
{
    internal const int LVM_FIRST = 0x1000;
    internal const int LVM_APPROXIMATEVIEWRECT = LVM_FIRST + 0x40;

    [DllImport("user32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    internal static extern int SendMessage(IntPtr hWnd, int uMsg, int wParam, int lParam);
}
Jimi
  • 29,621
  • 8
  • 43
  • 61
  • 1
    @dr.null Yes, that's possible. The OP didn't say. As you noted, when a new ClientSize is calculated, this measure can be applied to the ListView itself, or the difference between the previous and the new ClientSize can be added to the Form's size. I'll add an edit to include this use case. – Jimi May 20 '21 at 21:40