65.9K
CodeProject is changing. Read more.
Home

Auto Sizing WPF GridView Class

starIconstarIconstarIconemptyStarIconemptyStarIcon

3.00/5 (2 votes)

Aug 7, 2020

CPOL

3 min read

viewsIcon

15197

downloadIcon

738

Implements automatic column width sizing based on item contents for ListViews using GridView

AutoSizingGridView provides a convenient replacement for the default WPF GridView class, which implements automatic column width management, based on dynamic ListView content.

Introduction

WPF's ListView control is a useful tool for viewing a relatively small number of records of read-only fixed-format data. The default GridView class supplied with WPF automatically formats data into rows and columns, calculating the row height and column width based on the initial set of visible rows. This is sufficient for most cases, but can be limiting if the data is dynamic -- when new rows are added over time or the contents of visible records changes. The changed data values are displayed as truncated values when they don't fit into the existing column. The user can manually resize the columns to see the new data, but this may be inconvenient. Replacing the GridView class with AutoSizingGridView is an easy way to reduce the need for manually resizing ListView columns.

Using AutoSizingGridView

The AutoSizingGridView class is a drop-in replacement for WPF's GridView class. It's used as the View property of the ListView class:

<ListView x:Name="AutoSizedListView" SelectionMode="Extended"
          ItemsSource="{Binding RelativeSource=
                      {RelativeSource AncestorType=local:MainWindow}, Path=Items}">
    <ListView.View>
        <asgv:AutoSizingGridView x:Name="AutoSizedGridView" IsValueTrackingEnabled="True">
            <GridViewColumn Header="Name" 
            DisplayMemberBinding="{Binding Name, NotifyOnTargetUpdated=True}" />
            <GridViewColumn Header="Description" 
            DisplayMemberBinding="{Binding Description}" />
        </asgv:AutoSizingGridView>
    </ListView.View>
</ListView>

The only new property is the IsValueTrackingEnabled property, which determines if the <code>AutoSavingGridView will re-size when the contents of existing items is displayed (true). Setting the IsValueTrackingEnabled property to False inhibits value-change monitoring. Changed item values may still be displayed (as they usually are using GridView, if the source item implements INotifyPropertyChanged), but the value could be truncated. Change tracking is relatively expensive, so the property defaults to false.

Individual column widths can be set to be fixed, using XAML, programmatically, or manually by the user. AutoSavingGridView will not resize columns whose width has been set. Remaining columns will continue to be auto-sized.

Demonstration Application

A simple application is supplied to demonstrate how AutoSavingGridView and GridView react to changes in a ListView's items. You can use it to add items and change existing items, observing how they're displayed using both views.

Implementation

The AutoSizingGridView class is derived from the WPF GridView class. It overrides the GridView.PrepareItem method to receive notification when a new ListViewItem is ready to be displayed. An AutoSizingGridView instance can only be the member of one ListView's View property. Each ListView must have a dedicated AutoSavingGridView.

AutoSavingGridView will monitor column headers to ensure they fit, when the IsValueTrackingEnabled property is set to true. A change to a GridViewColumn's Header property may expand the column's width to ensure the header fits. Since the AutoSizingGridView instance doesn't become active until the first ListViewItem is prepared, changes to column widths are delayed until the first item is prepared.

AutoSavingGridView always checks new ListViewItems to ensure each cell's data can be displayed without truncation. Columns with fixed width are ignored. AutoSavingGridView does not shrink columns -- it only expands them when needed. Thus a column may become very wide to support a long data item, and will remain wide even when the item is removed or no longer visible. When the IsValueTrackingEnabled property is set to true, AutoSizingGridView also tries to track changes to individual cells in a row. If the column's DisplayMemberBinding has set NotifyOnTargetUpdated to true, the item's TargetUpdated event is hooked. Otherwise, the item's PropertyChanged event is used for tracking changes. This should be sufficient for simple text columns, but may not be sufficient for more complex or structured data.

History

  • 6th August, 2020: Initial version