Search code examples
wpfxamldatagridwpf-controls

Change DataGridColumnheader background on click of DatagridCell or current cell changed


The background of the column header of the current cell is changed when the CurrentCellChanged event is raised using this code in code-behind:

private void DataGrid_CurrentCellChanged(object sender, EventArgs e)
{
   foreach (var item in dataGrid.Columns)
   {
       if (item.HeaderStyle != null)
       {
           item.HeaderStyle = null;
       }
   }
   Style selectedColumnStyle = new Style(typeof(DataGridColumnHeader));
   selectedColumnStyle.Setters.Add(new Setter(DataGridColumnHeader.BackgroundProperty, Brushes.Gray));
   dataGrid.Columns[Index].HeaderStyle = selectedColumnStyle;
}

How to achieve same functionality in XAML using a style and triggers ?


Solution

  • I do not think that you can achieve this purely in XAML...but almost. You could create a column header style that changes the background, which is triggered by determining if the current cell column matches the column of the header that the style is applied to.

    <DataGrid ...>
       <DataGrid.Resources>
          <local:EqualityToBoolConverter x:Key="EqualityToBoolConverter"/>
       </DataGrid.Resources>
       <DataGrid.ColumnHeaderStyle>
          <Style TargetType="{x:Type DataGridColumnHeader}" BasedOn="{StaticResource {x:Type DataGridColumnHeader}}">
             <Style.Triggers>
                <DataTrigger Value="True">
                   <DataTrigger.Binding>
                      <MultiBinding Converter="{StaticResource EqualityToBoolConverter}">
                         <Binding RelativeSource="{RelativeSource Self}" Path="Column"/>
                         <Binding RelativeSource="{RelativeSource AncestorType={x:Type DataGrid}}" Path="CurrentCell.Column"/>
                      </MultiBinding>
                   </DataTrigger.Binding>
                   <Setter  Property="Background" Value="Gray"/>
                </DataTrigger>
             </Style.Triggers>
          </Style>
       </DataGrid.ColumnHeaderStyle>
     
       <!-- ...your markup. -->
    
    </DataGrid>
    

    As you can see, there is a multi binding that binds the column of the header the style is applied to and the column of the current cell. What we still need in code is a converter that checks for equality.

    public class EqualityToBoolConverter : IMultiValueConverter
    {
       public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
       {
          return values != null && values.Length > 0 && values.Skip(1).All(value => Equals(values[0], value));
       }
    
       public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
       {
          throw new InvalidOperationException("This conversion is one-way.");
       }
    }
    

    The DataTrigger then receives a boolean indicating, whether to apply the setters or not.