How to autosize and right-align GridViewColumn data in WPF?
How can I:
- right-align the text in the ID column
- make each of the columns auto size according to the text length of the cell with the longest visible data?
Here is the code:
<ListView Name="lstCustomers" ItemsSource="{Binding Path=Collection}">
<ListView.View>
<GridView>
<GridViewColumn Header="ID" DisplayMemberBinding="{Binding Id}" Width="40"/>
<GridViewColumn Header="First Name" DisplayMemberBinding="{Binding FirstName}" Width="100" />
<GridViewColumn Header="Last Name" DisplayMemberBinding="{Binding LastName}"/>
</GridView>
</ListView.View>
</ListView>
partial answer:
Thanks Kjetil, the GridViewColumn.CellTemplate works well and the Auto Width works of course but when the ObservativeCollection "Collection" is updated with longer-than-column-width data, the column sizes do not update themselves so that is only a solution for the initial display of data:
<ListView Name="lstCustomers" ItemsSource="{Binding Path=Collection}">
<ListView.View>
<GridView>
<GridViewColumn Header="ID" Width="Auto">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Id}" TextAlignment="Right" Width="40"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="First Name" DisplayMemberBinding="{Binding FirstName}" Width="Auto" />
<GridViewColumn Header="Last Name" DisplayMemberBinding="{Binding LastName}" Width="Auto"/>
</GridView>
</ListView.View>
</ListView>
To make each of the columns autosize you can set Width="Auto" on the GridViewColumn.
To right-align the text in the ID column you can create a cell template using a TextBlock and set the TextAlignment. Then set the ListViewItem.HorizontalContentAlignment (using a style with a setter on the ListViewItem) to make the cell template fill the entire GridViewCell.
Maybe there is a simpler solution, but this should work.
Note: the solution requires both HorizontalContentAlignment=Stretch in Window.Resources and TextAlignment=Right in the CellTemplate.
<Window x:Class="WpfApplication6.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<Window.Resources>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
</Style>
</Window.Resources>
<Grid>
<ListView Name="lstCustomers" ItemsSource="{Binding Path=Collection}">
<ListView.View>
<GridView>
<GridViewColumn Header="ID" Width="40">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Id}" TextAlignment="Right" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="First Name" DisplayMemberBinding="{Binding FirstName}" Width="Auto" />
<GridViewColumn Header="Last Name" DisplayMemberBinding="{Binding LastName}" Width="Auto"/>
</GridView>
</ListView.View>
</ListView>
</Grid>
</Window>
If the width of the contents changes, you'll have to use this bit of code to update each column:
private void ResizeGridViewColumn(GridViewColumn column)
{
if (double.IsNaN(column.Width))
{
column.Width = column.ActualWidth;
}
column.Width = double.NaN;
}
You'd have to fire it each time the data for that column updates.
If your listview is also re-sizing then you can use a behavior pattern to re-size the columns to fit the full ListView width. Almost the same as you using grid.column definitions
<ListView HorizontalAlignment="Stretch"
Behaviours:GridViewColumnResize.Enabled="True">
<ListViewItem></ListViewItem>
<ListView.View>
<GridView>
<GridViewColumn Header="Column *"
Behaviours:GridViewColumnResize.Width="*" >
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBox HorizontalAlignment="Stretch" Text="Example1" />
</DataTemplate>
</GridViewColumn.CellTemplate>
See the following link for some examples and link to source code http://lazycowprojects.tumblr.com/post/7063214400/wpf-c-listview-column-width-auto
I have created the following class and used across the application wherever required in place of GridView
:
/// <summary>
/// Represents a view mode that displays data items in columns for a System.Windows.Controls.ListView control with auto sized columns based on the column content
/// </summary>
public class AutoSizedGridView : GridView
{
protected override void PrepareItem(ListViewItem item)
{
foreach (GridViewColumn column in Columns)
{
// Setting NaN for the column width automatically determines the required
// width enough to hold the content completely.
// If the width is NaN, first set it to ActualWidth temporarily.
if (double.IsNaN(column.Width))
column.Width = column.ActualWidth;
// Finally, set the column with to NaN. This raises the property change
// event and re computes the width.
column.Width = double.NaN;
}
base.PrepareItem(item);
}
}
Since I had an ItemContainerStyle I had to put the HorizontalContentAlignment in the ItemContainerStyle
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=FieldDef.DispDetail, Mode=OneWay}" Value="False">
<Setter Property="Visibility" Value="Collapsed"/>
</DataTrigger>
</Style.Triggers>
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
....