We use the ListView to display our report list and Inside ListView is GridView. One of the feature is auto increasing the column width as needed. GridView column header provides this auto expanding column width by dragging on column header border.
Since the report list also needs to sort on column headers, we have implement the following code and we lose the column expand feature.
using System.ComponentModel; using System.Windows; using System.Windows.Controls; using System.Windows.Data; namespace CommonControls.Helper { public static class GridViewSort { #region Not Sorted Style Property private static readonly DependencyProperty NotSortedStyleProperty = DependencyProperty.RegisterAttached( "NotSortedStyle", typeof(Style), typeof(GridViewSort), new PropertyMetadata(null)); public static Style GetNotSortedStyle(DependencyObject obj) { return obj != null ? (Style)obj.GetValue(NotSortedStyleProperty) : null; } public static void SetNotSortedStyle(DependencyObject obj, Style value) { if (obj != null) { obj.SetValue(NotSortedStyleProperty, value); } } #endregion #region Ascending Style Property private static readonly DependencyProperty AscendingStyleProperty = DependencyProperty.RegisterAttached( "AscendingStyle", typeof(Style), typeof(GridViewSort), new PropertyMetadata(null)); public static Style GetAscendingStyle(DependencyObject obj) { return obj != null ? (Style)obj.GetValue(AscendingStyleProperty) : null; } public static void SetAscendingStyle(DependencyObject obj, Style value) { if (obj != null) { obj.SetValue(AscendingStyleProperty, value); } } #endregion #region Descending Style Property private static readonly DependencyProperty DescendingStyleProperty = DependencyProperty.RegisterAttached( "DescendingStyle", typeof(Style), typeof(GridViewSort), new PropertyMetadata(null)); public static Style GetDescendingStyle(DependencyObject obj) { return obj != null ? (Style)obj.GetValue(DescendingStyleProperty) : null; } public static void SetDescendingStyle(DependencyObject obj, Style value) { if (obj != null) { obj.SetValue(DescendingStyleProperty, value); } } #endregion #region Active Sort Direction Property private static readonly DependencyPropertyKey ActiveSortDirectionPropertyKey = DependencyProperty.RegisterAttachedReadOnly( "ActiveSortDirection", typeof(ListSortDirection), typeof(GridViewSort), new PropertyMetadata(ListSortDirection.Ascending)); public static ListSortDirection GetActiveSortDirection(DependencyObject obj) { return obj != null ? (ListSortDirection)obj.GetValue(ActiveSortDirectionPropertyKey.DependencyProperty) : ListSortDirection.Ascending; } private static void SetActiveSortDirection(DependencyObject obj, ListSortDirection value) { obj.SetValue(ActiveSortDirectionPropertyKey, value); } #endregion #region Active Sort Header Property private static readonly DependencyPropertyKey ActiveSortHeaderPropertyKey = DependencyProperty.RegisterAttachedReadOnly( "ActiveSortHeader", typeof(GridViewColumnHeader), typeof(GridViewSort), new PropertyMetadata(null)); public static GridViewColumnHeader GetActiveSortHeader(DependencyObject obj) { return obj != null ? (GridViewColumnHeader)obj.GetValue(ActiveSortHeaderPropertyKey.DependencyProperty) : null; } private static void SetActiveSortHeader(DependencyObject obj, GridViewColumnHeader value) { obj.SetValue(ActiveSortHeaderPropertyKey, value); } #endregion #region Allow Sorting Property private static readonly RoutedEventHandler GridViewHeaderClickEventHandler = new RoutedEventHandler(GridViewHeaderClickHandler); private static void GridViewHeaderClickHandler(object sender, RoutedEventArgs args) { ListView control = sender as ListView; GridViewColumnHeader header = args.OriginalSource as GridViewColumnHeader; if (control != null && header != null && header.Column != null) { GridViewColumnHeader active = GetActiveSortHeader(control); ListSortDirection direction = GetActiveSortDirection(control); ICollectionView collection = CollectionViewSource.GetDefaultView(control.ItemsSource); string path = (header.Column.DisplayMemberBinding as Binding).Path.Path; // Note that this will only work for Binding! if (active != null) { if (active.Equals(header)) { direction = direction == ListSortDirection.Ascending ? ListSortDirection.Descending : ListSortDirection.Ascending; } else { direction = ListSortDirection.Ascending; // Reset to ascending active.Column.HeaderContainerStyle = GetNotSortedStyle(control); } } else { GridView grid = control.View as GridView; if (grid != null) { foreach (GridViewColumn column in grid.Columns) { column.HeaderContainerStyle = GetNotSortedStyle(control); } } } header.Column.HeaderContainerStyle = direction == ListSortDirection.Ascending ? GetAscendingStyle(control) : GetDescendingStyle(control); SetActiveSortDirection(control, direction); SetActiveSortHeader(control, header); collection.SortDescriptions.Clear(); collection.SortDescriptions.Add(new SortDescription(path, direction)); collection.Refresh(); } } private static readonly DependencyProperty AllowSortingProperty = DependencyProperty.RegisterAttached( "AllowSorting", typeof(bool), typeof(GridViewSort), new PropertyMetadata(false, (sender, args) => { ListView control = sender as ListView; if (control != null && (bool)args.NewValue) { control.AddHandler(GridViewColumnHeader.ClickEvent, GridViewHeaderClickEventHandler); } if (control != null && !((bool)args.NewValue)) { control.RemoveHandler(GridViewColumnHeader.ClickEvent, GridViewHeaderClickEventHandler); } })); public static bool GetAllowSorting(DependencyObject obj) { return obj != null ? (bool)obj.GetValue(AllowSortingProperty) : false; } public static void SetAllowSorting(DependencyObject obj, bool value) { if (obj != null) { obj.SetValue(AllowSortingProperty, value); } } #endregion } }
<ListView Grid.Row="0" Margin="0,5,0,5" IsSynchronizedWithCurrentItem="True" x:Name="Reportslist" ItemsSource="{Binding ReportLists, UpdateSourceTrigger=PropertyChanged}" SelectedItem="{Binding Path=SelectReport, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" helper:GridViewSort.AllowSorting="True" helper:GridViewSort.NotSortedStyle="{StaticResource GridViewColumnHeaderNotSorted}" helper:GridViewSort.AscendingStyle="{StaticResource GridViewColumnHeaderSortAscending}" helper:GridViewSort.DescendingStyle="{StaticResource GridViewColumnHeaderSortDescending}"><ListView.View ><GridView x:Name="gridViewReports" AllowsColumnReorder="true"><GridViewColumn Header="{Binding Path=General_Date, FallbackValue='Date FB'}" Width="180" x:Name="Date" HeaderContainerStyle="{StaticResource GridViewColumnHeaderSortDescending}" DisplayMemberBinding="{Binding Path=StartDateTime, StringFormat=MM-dd-yyyy hh:mm tt}"/><GridViewColumn Header="{Binding Path=General_Name, FallbackValue='Run Name FB'}" Width="200" x:Name="Name" DisplayMemberBinding="{Binding Path=Name}"/> ......
</GridView>
</ListView.View></ListView>
define styles as following so when clicking on column header, it will show the UpArrow or DownArrow to indicate sorting order.
<Style x:Key="DownArrow" TargetType="{x:Type Path}"><Setter Property="HorizontalAlignment" Value="Left" /><Setter Property="VerticalAlignment" Value="Center" /><Setter Property="Margin" Value="15,0,0,0" /><Setter Property="MaxHeight" Value="10" /><Setter Property="Fill" Value="Black" /><Setter Property="Stroke" Value="Black" /><Setter Property="Stretch" Value="Uniform" /><Setter Property="RenderTransformOrigin" Value="0.5,0.5" /><Setter Property="Data" Value="M518.892,16.380827 L534.22536,16.380827 526.89219,24.047667 z" /></Style><!-- Base style for sortable grid view column --><Style x:Key="GridViewColumnHeaderNotSorted" TargetType="{x:Type GridViewColumnHeader}"><Setter Property="Margin" Value="0,0,0,0" /><Setter Property="Padding" Value="1,1,1,1" /><Setter Property="FontSize" Value="18" /><Setter Property="HorizontalContentAlignment" Value="Center" /><Setter Property="VerticalContentAlignment" Value="Center" /><Setter Property="Background" Value="LightGray" /><Setter Property="Foreground" Value="Black" /><Setter Property="Template"><Setter.Value><ControlTemplate TargetType="{x:Type GridViewColumnHeader}"><Border BorderBrush="LightGray" Background="{TemplateBinding Background}" BorderThickness="0,0,2,2" Padding="2,0,0,0" Margin="2,0,0,0"><TextBlock Text="{TemplateBinding Content}" VerticalAlignment="Center" TextAlignment="Center" Margin="0,2" Background="Transparent" /></Border></ControlTemplate></Setter.Value></Setter></Style><Style x:Key="GridViewColumnHeaderSortAscending" TargetType="{x:Type GridViewColumnHeader}" BasedOn="{StaticResource GridViewColumnHeaderNotSorted}"><Setter Property="Template"><Setter.Value><ControlTemplate TargetType="{x:Type GridViewColumnHeader}"><Border BorderBrush="LightGray" Background="{TemplateBinding Background}" BorderThickness="0,0,2,2" Padding="2,0,0,0" Margin="2,0,0,0"><Grid><Grid.ColumnDefinitions><ColumnDefinition Width="*"/><ColumnDefinition Width="Auto"/><ColumnDefinition Width="20"/></Grid.ColumnDefinitions><Path Style="{StaticResource DownArrow}" Grid.Column="1"><Path.RenderTransform><ScaleTransform ScaleY="-1" /></Path.RenderTransform></Path><TextBlock Text="{TemplateBinding Content}" TextAlignment="Center" VerticalAlignment="Center" Margin="0,2" Background="Transparent" /></Grid></Border></ControlTemplate></Setter.Value></Setter></Style><Style x:Key="GridViewColumnHeaderSortDescending" TargetType="{x:Type GridViewColumnHeader}" BasedOn="{StaticResource GridViewColumnHeaderNotSorted}"><Setter Property="Template"><Setter.Value><ControlTemplate TargetType="{x:Type GridViewColumnHeader}"><Border BorderBrush="LightGray" Background="{TemplateBinding Background}" BorderThickness="0,0,2,2" Padding="2,0,0,0" Margin="2,0,0,0"><Grid><Grid.ColumnDefinitions><ColumnDefinition Width="*"/><ColumnDefinition Width="Auto"/><ColumnDefinition Width="20"/></Grid.ColumnDefinitions><TextBlock Text="{TemplateBinding Content}" TextAlignment="Center" VerticalAlignment="Center" Margin="0,2" Background="Transparent" /><Path Style="{StaticResource DownArrow}" Grid.Column="1" VerticalAlignment="Center"/></Grid></Border></ControlTemplate></Setter.Value></Setter></Style>
Do we missing anything in GridViewSort class?
If we want to keep the column width expand feature, can we still use "GridViewSort" class? Thx!
JaneC