The DataGridView provides many options when it comes to defining the width of each column. My personal favorite is to set the AutoSizeMode property to Fill and then define a FillWeight for each column. Doing such will automatically resize each column according to its FillWeight property no matter how the user resizes the form. I was looking for such a property when using the ListView control in detail mode but apparently there is no such feature.
According to the MSDN documentation here, setting the column header Width property to -1 will automatically adjust the column width to the longest item in the column and setting the column header Width property to -2 will automatically adjust the width of the column to the size of the column heading. But, there is no Fill setting that will automatically adjust each column proportionality like is done in the DataGridView.
The simplest solution here is to just use a DataGridView and drop the ListView entirely, but in my situation, the ListView rendered the data much more to my liking that I could get the DataGridView to do. Given that no such solution was available, I decided to write one up myself using the ListView.SizeChanged event. The ListView.SizeChanged event is fired every time the size of the ListView changes, obviously, and thus with a bit of logic in this event we can programmatically emulate the auto sizing of the columns as done in the DataGridView.
Disclaimer: The best way to implement this is to create a custom control derived from the ListView class that contains the following logic. For simplicity, I have just used the stock ListView control and the SizeChanged event.
At design time when you define the ListView columns, enter the desired FillWeight of the column as an integer in the Tag property. Originally I tried just using the Width property but ran into problems recovering the correct value when the calculated width went to zero. If we set the FillWeight in the Tag property, it will stay constant for the life of the control (if you can ensure it isn’t changed at runtime). Again, ideally if you created a custom control, you could create a custom FillWeight property instead of using the Tag property,
Then, place the code that follows in the SizeChanged event. This code calculates the percentage of space each column should occupy and then sets the width of the column appropriately depending on the visible space the ListView control occupies. When resizing the ListView, this code is called multiple times. In an effort to reduce the number of calculations performed, we use the Resizing flag.
private bool Resizing = false;
private void ListView_SizeChanged(object sender, EventArgs e)
{
// Don't allow overlapping of SizeChanged calls
if (!Resizing)
{
// Set the resizing flag
Resizing = true;
ListView listView = sender as ListView;
if (listView != null)
{
float totalColumnWidth = 0;
// Get the sum of all column tags
for (int i = 0; i < listView.Columns.Count; i++)
totalColumnWidth += Convert.ToInt32(listView.Columns[i].Tag);
// Calculate the percentage of space each column should
// occupy in reference to the other columns and then set the
// width of the column to that percentage of the visible space.
for (int i = 0; i < listView.Columns.Count; i++)
{
float colPercentage = (Convert.ToInt32(listView.Columns[i].Tag) / totalColumnWidth);
listView.Columns[i].Width = (int)(colPercentage * listView.ClientRectangle.Width);
}
}
}
// Clear the resizing flag
Resizing = false;
}
In the example below, there are three columns with FillWeights of 1, 2, and 1 respectively. Thus, the first and third column should occupy 25% of the ListView’s visible space and the second should occupy 50%. The results of the automatic sizing are shown for various form widths below.
Note that if you have multiple ListView controls on a form for which you want to use this logic, you can just hook up each SizeChanged event with the same code as shown below. For this reason, I casted the sender object to a ListView instead of just referencing it directly.
public Form1()
{
InitializeComponent();
this.listView1.SizeChanged += new EventHandler(ListView_SizeChanged);
this.listView2.SizeChanged += new EventHandler(ListView_SizeChanged);
this.listView3.SizeChanged += new EventHandler(ListView_SizeChanged);
}



April 20, 2011 at 1:03 pm
Excellent. Just what I needed and well executed.
Thanks.
September 8, 2011 at 9:03 am
Perfect! Just what I needed at the moment!
November 9, 2011 at 5:24 pm
Thanks Nick! Not 100% for sure but I’m 99.99% that you’re the ONLY person who’s actually provided the solution to the problem that was at hand. EVERY thread and/or post I’ve see so far DON’T address how to resize listview control dynamically according to winForm size! Thx again and take care!
-Dee
November 9, 2011 at 6:11 pm
can someone give an example of implementing this code within a custom listview control?
November 29, 2011 at 4:16 am
Thanks alot !! The code was what I needed.
November 30, 2011 at 11:00 am
Thanks for the post, Nick. This works fine until the ListView is resized vertically when: 1) a vertical scrollbar is present and 2) the scrollbar is scrolled at least some of the way down. I have my custom ListView inside of a SplitContainer and when the horizontal split bar is dragged to expand the ListView you get empty rows at the top of the ListView and it gets worse: a subsequent click on an item will make all the items disappear (they will not paint). I’m not doing any other processing. Very annoying. Refresh() nor Invalidate() resolve the painting issue. Thoughts?
November 30, 2011 at 9:31 pm
No solution off the top of my head. Do you have a sample project I could take a look at?
June 23, 2012 at 8:57 am
Great solution
June 23, 2012 at 9:00 am
I just added two lines of code and then the Taks on UI was done perfectly
// Don’t allow overlapping of SizeChanged calls
if (!Resizing)
{
// Set the resizing flag
Resizing = true;
ListView listView = sender as ListView;
listView.BeginUpdate();
if (listView != null)
{
float totalColumnWidth = 0;
// Get the sum of all column tags
for (int i = 0; i < listView.Columns.Count; i++)
totalColumnWidth += Convert.ToInt32(listView.Columns[i].Tag);
// Calculate the percentage of space each column should
// occupy in reference to the other columns and then set the
// width of the column to that percentage of the visible space.
for (int i = 0; i < listView.Columns.Count; i++)
{
float colPercentage = (Convert.ToInt32(listView.Columns[i].Tag) / totalColumnWidth);
listView.Columns[i].Width = (int)(colPercentage * listView.ClientRectangle.Width);
}
}
listView.EndUpdate();
}
// Clear the resizing flag
Resizing = false;
August 31, 2012 at 1:23 pm
I PERFECTED THIS
to the point where u dont need to use tags.. or use a constant.. it will change the ratio only when user change it and when the window size change it will change with it
private void Form1_Load(object sender, EventArgs e)
{
int totalW = listView1.Width;
for (int i = 0; i < listView1.Columns.Count – 1; i++)
{
listView1.Columns[i].Tag = (decimal)listView1.Columns[i].Width / (decimal)totalW;
}
}
private void Form1_Resize(object sender, EventArgs e)
{
int totalW = listView1.Width;
for (int i = 0; i < listView1.Columns.Count – 1; i++)
{
listView1.Columns[i].Width = Convert.ToInt32(totalW * (decimal)listView1.Columns[i].Tag);
}
}
private void listView1_ColumnWidthChanging(object sender, ColumnWidthChangingEventArgs e)
{
int totalW = listView1.Width;
for (int i = 0; i < listView1.Columns.Count – 1; i++)
{
listView1.Columns[i].Tag = (decimal)listView1.Columns[i].Width / (decimal)totalW;
}
}
August 31, 2012 at 1:41 pm
***I PERFECTED THIS
To make it dinamic! it will change the ratio only when user change it and when the window size change it will change with it
private void Form1_Load(object sender, EventArgs e)
{
int totalW = listView1.Width;
for (int i = 0; i < listView1.Columns.Count; i++)
{
listView1.Columns[i].Tag = (decimal)listView1.Columns[i].Width / (decimal)totalW;
}
}
private void Form1_Resize(object sender, EventArgs e)
{
int totalW = listView1.Width;
for (int i = 0; i < listView1.Columns.Count ; i++)
{
listView1.Columns[i].Width = Convert.ToInt32(totalW * (decimal)listView1.Columns[i].Tag);
}
}
private void listView1_ColumnWidthChanging(object sender, ColumnWidthChangingEventArgs e)
{
int totalW = listView1.Width;
for (int i = 0; i < listView1.Columns.Count ; i++)
{
listView1.Columns[i].Tag = (decimal)listView1.Columns[i].Width / (decimal)totalW;
}
}
October 15, 2012 at 1:02 am
could anyone clear this doubt ………..
i have a list view and there are multiple columns with long text values………..
like a column with destination file path
it has a value like c:\users\kavya\new\coding\img1000.jpg
something very big…………
i want to adjust the text according to size of the column
when the users uses the scroll bar:
with width something very big all the data c:\users\kavya\new\coding\img1000.jpg
should be visible
and when he scrolls the column header to very small only the c:\img1000.jpg has to be viewd ,but the memory should have the entire path
actualy we see something like c:\users\kavya….. i dont want this way …..
is there any solution please any help would be appreciated…
thanks