Let\'s say I have the following ListView:
There is no easy way to do this with a GridListView since it doesn't support setting the width of a column to "*" (fill remaining space).
Here is a discussion of how you could fake it by using an IValueConverter to set the width of the column to TotalListWidth - SumOfColumnWidths
On the other hand, have you considered using a DataGrid instead? This will support the kind of layout you are looking for, though is a considerably heavier control. It is also only native in .NET 4 - though you can get an equivalent for 3.5 through the WPF Toolkit.
<Grid Name="dummygrid" Visibility="Hidden">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.5*"></ColumnDefinition>
<ColumnDefinition Width="0.2*"></ColumnDefinition>
<ColumnDefinition Width="0.1*"></ColumnDefinition>
<ColumnDefinition Width="0.2*"></ColumnDefinition>
<ColumnDefinition Width="150"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Border Grid.Column="0" Name="dummywidth1"></Border>
<Border Grid.Column="1" Name="dummywidth2"></Border>
<Border Grid.Column="2" Name="dummywidth3"></Border>
<Border Grid.Column="3" Name="dummywidth4"></Border>
<Border Grid.Column="5" Name="dummywidth5"></Border>
</Grid>
<ListView Name="Installer_LV" Grid.Row="1" ItemContainerStyle="{StaticResource LV_ItemStyle}" ScrollViewer.HorizontalScrollBarVisibility="Disabled" AlternationCount="2">
<ListView.View>
<GridView ColumnHeaderContainerStyle="{StaticResource LV_HeaderStyle}">
<GridViewColumn Width="{Binding ElementName=dummywidth1, Path=ActualWidth}" DisplayMemberBinding="{Binding DisplayName}" >
<GridViewColumn.Header>
<GridViewColumnHeader Tag="DisplayName" Click="InstallerLV_HeaderClick">Name</GridViewColumnHeader>
</GridViewColumn.Header>
</GridViewColumn>
<GridViewColumn Width="{Binding ElementName=dummywidth2, Path=ActualWidth}" DisplayMemberBinding="{Binding Publisher}">
<GridViewColumn.Header>
<GridViewColumnHeader Tag="Publisher" Click="InstallerLV_HeaderClick">Publisher</GridViewColumnHeader>
</GridViewColumn.Header>
</GridViewColumn>
<GridViewColumn Width="{Binding ElementName=dummywidth3, Path=ActualWidth}" DisplayMemberBinding="{Binding Version}">
<GridViewColumn.Header>
<GridViewColumnHeader Tag="Version" Click="InstallerLV_HeaderClick">Version</GridViewColumnHeader>
</GridViewColumn.Header>
</GridViewColumn>
<GridViewColumn Width="{Binding ElementName=dummywidth4, Path=ActualWidth}" DisplayMemberBinding="{Binding Size}">
<GridViewColumn.Header>
<GridViewColumnHeader Tag="Size" Click="InstallerLV_HeaderClick">Size</GridViewColumnHeader>
</GridViewColumn.Header>
</GridViewColumn>
<GridViewColumn Header="Action" Width="150">
<GridViewColumn.CellTemplate>
<DataTemplate>
<Button Height="38" Width="130" Style="{DynamicResource RoundedButton}" Content="{Binding Status}" Tag="{Binding ModuleId}" HorizontalAlignment="Center" VerticalAlignment="Center" Click="onActionClick"></Button>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
In the above example i have used a dummy grid and split into 5 columns and using binding assign that size to "GridViewColum" by
Width="{Binding ElementName=dummywidth4, Path=ActualWidth}"
So that when the hidden dummy grid column size changes it will get reflect in gridview column size also.
Try this code instead,
private void Window_SizeChanged(object sender, SizeChangedEventArgs e)
{
double remainingSpace = mylistviewname.ActualWidth;
if (remainingSpace > 0)
{
(mylistviewname.View as GridView).Columns[1].Width = Math.Ceiling(remainingSpace / 3);
(mylistviewname.View as GridView).Columns[2].Width = Math.Ceiling(remainingSpace / 3);
(mylistviewname.View as GridView).Columns[3].Width = Math.Ceiling(remainingSpace / 3);
}
}
Here i user SizeChanged event so when the windows size change this function is triggered and update the width of the listviewheader. I have 3 listviewheaders so divided by 3 if you have more than 3 divide by appropriate value.
Set Width="Auto"
on your GridViewColumns. However, due to virtualization you may encounter some problems with auto-sizing.
See this question.
So, long-story-short, if you want accurate auto-sizing of columns you'll need to recalculate your widths when the visible data changes, due to virtualization.
I'd like to present an another approach in order to size each column with the largest element width. Do this following on each list view item with the help of a loop.
No need to change size after a re-size window event.
Leaves UnitWidth as the constant font width size.
You can also define a delegate to the SourceUpdated event.
GridView gv = (myListView.View as GridView);
if (titleLen < c.Title.Length)
{
titleLen = c.Title.Length;
gv.Columns[0].Width = titleLen * UnitWidth;
}
if (cssLen < c.CSSName.Length)
{
cssLen = c.CSSName.Length;
gv.Columns[1].Width = cssLen * UnitWidth;
}
if (valueLen < c.Value.Length)
{
valueLen = c.Value.Length;
gv.Columns[2].Width = valueLen * UnitWidth;
}
First set the name in the column header like so:
<GridViewColumn Header="Description" Width="350" x:Name="lvhDescription"/>
And then on resize modify width.
Private Sub winMain_SizeChanged(sender As Object, e As SizeChangedEventArgs) Handles Me.SizeChanged
If Me.IsLoaded = False Then Exit Sub
lvhDescription.Width = e.NewSize.Width - 665
End Sub