A similar question suggested using an ObjectList, but it looked like overkill for what I wanted. So instead, I made this simple overload (below) to resize based on the items in the list.
I've only tested this displaying in details mode on Windows Vista, but it's simple and seems to work well.
#pragma once
/// <summary>
/// A ListView based control which adds a method to resize itself to show all
/// items inside it.
/// </summary>
public ref class ResizingListView :
public System::Windows::Forms::ListView
{
public:
/// <summary>
/// Constructs a ResizingListView
/// </summary>
ResizingListView(void);
/// <summary>
/// Works out the height of the header and all the items within the control
/// and resizes itself so that all items are shown.
/// </summary>
void ResizeToItems(void)
{
// Work out the height of the header
int headerHeight = 0;
int itemsHeight = 0;
if( this->Items->Count == 0 )
{
// If no items exist, add one so we can use it to work out
this->Items->Add("");
headerHeight = GetHeaderSize();
this->Items->Clear();
itemsHeight = 0;
}
else
{
headerHeight = GetHeaderSize();
itemsHeight = this->Items->Count*this->Items[0]->Bounds.Height;
}
// Work out the overall height and resize to it
System::Drawing::Size sz = this->Size;
int borderSize = 0;
if( this->BorderStyle != System::Windows::Forms::BorderStyle::None )
{
borderSize = 2;
}
sz.Height = headerHeight+itemsHeight+borderSize;
this->Size = sz;
}
protected:
/// <summary>
/// Grabs the top of the first item in the list to work out how tall the
/// header is. Note: There _must_ at least one item in the list or an
/// exception will be thrown
/// </summary>
/// <returns>The height of the header</returns>
int GetHeaderSize(void)
{
return Items[0]->Bounds.Top;
}
};