How to autosize and right-align GridViewColumn data in WPF?

158,562

Solution 1

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>

Solution 2

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.

Solution 3

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

Solution 4

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);
    }
}

Solution 5

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" /> 
    ....
Share:
158,562
Angry Dan
Author by

Angry Dan

web/software developer, .NET, C#, WPF, PHP, software trainer, English teacher, have philosophy degree, love languages, run marathons my tweets: http://www.twitter.com/edward_tanguay my runs: http://www.tanguay.info/run my code: http://www.tanguay.info/web my publications: PHP 5.3 training video (8 hours, video2brain) my projects: http://www.tanguay.info

Updated on July 08, 2022

Comments

  • Angry Dan
    Angry Dan almost 2 years

    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>
    
  • Gishu
    Gishu about 14 years
    @Kjetil - Can I apply this setting to a specific column ?
  • Armentage
    Armentage over 13 years
    What would you attach this to?
  • RandomEngy
    RandomEngy over 13 years
    Run it manually on the GridViewColumn after you've updated the grid data. If you've got a ViewModel you could subscribe to the PropertyChanged event on it and run it then.
  • gehho
    gehho over 13 years
    +1 Thanks for that! This helped me a lot! Not related to this question, but anyway: I implemented a customized List/GridView where you can dynamically add/remove columns at runtime via the GUI. However, when I removed and re-added a column, it no longer appeared. First, I thought it was not added at all (for some reason), but then (using Snoop) I found out that it is actually added, but has an ActualWidth of 0 (it was auto-sized and obviously reset when the column was removed). Now, I use your code to set the column to the correct width after I re-added it to the Columns. Many thanks!
  • Helge Klein
    Helge Klein over 13 years
    +1 for: <Setter Property="HorizontalContentAlignment" Value="Stretch" />
  • Designpattern
    Designpattern over 12 years
    This one is cool. Solves the problem and gives you all the , n, Auto functionality you are looking for.
  • Jake Berger
    Jake Berger over 12 years
    THIS is what I was looking for. :D
  • Jake Berger
    Jake Berger over 12 years
    Note: there seems to be a bug. When the ListView is resized vertically, to the point that causes a vertical scrollbar to appear, the column will continuously increase in width until the scrollbar disappears.
  • Jake Berger
    Jake Berger over 12 years
    This post may provide insight on the behavior described in my previous comment.
  • Gqqnbig
    Gqqnbig almost 12 years
    It's cool, I mean both the code and the site:). I believe it will be useful when I have stricter requirements.
  • Gqqnbig
    Gqqnbig almost 12 years
    A simple solution to my problem!
  • Nitin Chaudhari
    Nitin Chaudhari over 11 years
    awesome, but I have 15 columns, is there any way I dont have to repeat the celltemplate for all of them?
  • floele
    floele about 11 years
    It also doesn't work if you forget to remove the DisplayMemberBinding from the GridViewColumn. The template won't have any effect then.
  • K0D4
    K0D4 about 11 years
    +1 Perfect! Wish this was marked as the answer. I added x:Name="gvcMyColumnName" to the XAML where the column was defined so I could access it in the code behind. Works like a champ.
  • It'sNotALie.
    It'sNotALie. over 10 years
    @Mohamed Why isn't it?
  • B.K.
    B.K. about 10 years
    You have width of GridViewColumn as 40 and you set column definition width to Auto? That doesn't make sense.
  • Boumbles
    Boumbles about 8 years
    Does anybody have a link to the source code? It was hosted on Google code and exporting it to Github doesn't show any more source.
  • Rolf Wessels
    Rolf Wessels about 8 years
    Hmm, I see what you mean. I will go and check at home to see if I still have a backup somewhere.
  • Chris
    Chris about 8 years
    Seems to only resize based on visible data (so, the first X rows), not necessarily the longest value for each column. Still nice though.
  • David
    David almost 8 years
    Width="Auto" seems to have no effect
  • J. Andersen
    J. Andersen about 6 years
    This inspired me to this solution to fill the width of one column: <GridViewColumn Width="{Binding RelativeSource={RelativeSource AncestorType=ListView}, Path=ActualWidth}" >