0

I have a DataGrid with RowHeaders. These RowHeaders are displayed in, what I would call the first column of the grid. All the "data" columns have a header with the name of the column in it. The "first column" that contains the row header does not have such a "header". Is it possible to capture click events on that "header"? To make clear what "header" I mean, here an image:

enter image description here

EDIT:

This is my DataGrid definition including the code from @EldHasp answer

<DataGrid Name="TenantsGrid"
          Style="{StaticResource DataGridStyle}"
          d:ItemsSource="{Binding TenantGridDataSource}"
          AutoGenerateColumns="False"
          CanUserResizeRows="False"
          SelectionMode="Single"
          IsReadOnly="True"
          SelectedItem="{Binding SelectedTenant}" Margin="10,0,11,10">

    <FrameworkElement.Resources>
        <Style x:Key="{ComponentResourceKey ResourceId=DataGridSelectAllButtonStyle, TypeInTargetAssembly={x:Type DataGrid}}"
            TargetType="{x:Type Button}"
            BasedOn="{StaticResource {ComponentResourceKey ResourceId=DataGridSelectAllButtonStyle, TypeInTargetAssembly={x:Type DataGrid}}}">
            <EventSetter Event="Click" Handler="OnClickSelectAll"/>
        </Style>
    </FrameworkElement.Resources>

    <DataGrid.Columns>
        <DataGridTextColumn     Header="Nachname" Width="Auto" Binding="{Binding LastName}"    CanUserSort="True"/>
        <DataGridTextColumn     Header="Vorname"  Width="Auto" Binding="{Binding FirstName}"   CanUserSort="True"/>
        <DataGridTextColumn     Header="eMail"    Width="Auto" Binding="{Binding EMail}"       CanUserSort="False"/>
        <DataGridTextColumn     Header="Telefon"  Width="Auto" Binding="{Binding PhoneNumber}" CanUserSort="False"/>
        <DataGridTextColumn     Header="Notizen"  Width="*"    Binding="{Binding Notes}"       CanUserSort="False"/>

        <DataGridCheckBoxColumn Width="Auto" Binding="{Binding Flagged}" CanUserSort="False">
            <DataGridCheckBoxColumn.Header>
                <TextBlock Text="M" ToolTip="Markiert - Auf Notizen achten!" />
            </DataGridCheckBoxColumn.Header>
        </DataGridCheckBoxColumn>
        <DataGridCheckBoxColumn Width="Auto" Binding="{Binding Blocked}" CanUserSort="False">
            <DataGridCheckBoxColumn.Header>
                <TextBlock Text="B" ToolTip="Blockiert - Keine weitere Buchung annehmen!" />
            </DataGridCheckBoxColumn.Header>
        </DataGridCheckBoxColumn>
    </DataGrid.Columns>

    <DataGrid.ColumnHeaderStyle>
        <Style TargetType="DataGridColumnHeader">
            <EventSetter Event="Click" Handler="OnColumnHeaderClicked"/>
        </Style>
    </DataGrid.ColumnHeaderStyle>
    
    <DataGrid.RowStyle>
        <Style TargetType="{x:Type DataGridRow}">
            <Style.Triggers>
                <DataTrigger Binding="{Binding Flagged}" Value="True">
                    <Setter Property="Background" Value="#F1F5E4"/>
                </DataTrigger>
                <DataTrigger Binding="{Binding Blocked}" Value="True">
                    <Setter Property="Background" Value="#DDD5C3"/>
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </DataGrid.RowStyle>
    
</DataGrid>

DataGridStyle is:

<Style x:Key="DataGridStyle" TargetType="DataGrid">
    <Setter Property="RowHeaderStyle" Value="{DynamicResource GridRowHeaderStyle}"/>
</Style>

<Style x:Key="GridRowHeaderStyle" TargetType="DataGridRowHeader">
    <Setter Property="Width" Value="20"/>
    <Style.Triggers>
        <Trigger Property="IsRowSelected" Value="True">
            <Setter Property="FontFamily" Value="Segoe UI"/>
            <Setter Property="FontSize" Value="12"/>
            <Setter Property="Foreground" Value="Gray"/>
            <Setter Property="HorizontalContentAlignment" Value="Center"/>
            <Setter Property="Padding" Value="5 0"/>
            <Setter Property="Content" Value="●"/>
        </Trigger>
    </Style.Triggers>
</Style>

1 Answer 1

1

Here is the default DataGrid template:

        <Style x:Key="{ComponentResourceKey ResourceId=DataGridSelectAllButtonStyle, TypeInTargetAssembly={x:Type DataGrid}}" TargetType="{x:Type Button}">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type Button}">
                        <Grid>
                            <Rectangle x:Name="Border" Fill="{DynamicResource {x:Static SystemColors.ControlBrushKey}}" SnapsToDevicePixels="True"/>
                            <Polygon x:Name="Arrow" Fill="Black" HorizontalAlignment="Right" Margin="8,8,3,3" Opacity="0.15" Points="0,10 10,10 10,0" Stretch="Uniform" VerticalAlignment="Bottom"/>
                        </Grid>
                        <ControlTemplate.Triggers>
                            <Trigger Property="IsMouseOver" Value="True">
                                <Setter Property="Stroke" TargetName="Border" Value="{DynamicResource {x:Static SystemColors.ControlDarkBrushKey}}"/>
                            </Trigger>
                            <Trigger Property="IsPressed" Value="True">
                                <Setter Property="Fill" TargetName="Border" Value="{DynamicResource {x:Static SystemColors.ControlDarkBrushKey}}"/>
                            </Trigger>
                            <Trigger Property="IsEnabled" Value="False">
                                <Setter Property="Visibility" TargetName="Arrow" Value="Collapsed"/>
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
        <Style TargetType="{x:Type DataGrid}">
            <Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"/>
            <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
            <Setter Property="BorderBrush" Value="#FF688CAF"/>
            <Setter Property="BorderThickness" Value="1"/>
            <Setter Property="RowDetailsVisibilityMode" Value="VisibleWhenSelected"/>
            <Setter Property="ScrollViewer.CanContentScroll" Value="true"/>
            <Setter Property="ScrollViewer.PanningMode" Value="Both"/>
            <Setter Property="Stylus.IsFlicksEnabled" Value="False"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type DataGrid}">
                        <Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Padding="{TemplateBinding Padding}" SnapsToDevicePixels="True">
                            <ScrollViewer x:Name="DG_ScrollViewer" Focusable="false">
                                <ScrollViewer.Template>
                                    <ControlTemplate TargetType="{x:Type ScrollViewer}">
                                        <Grid>
                                            <Grid.ColumnDefinitions>
                                                <ColumnDefinition Width="Auto"/>
                                                <ColumnDefinition Width="*"/>
                                                <ColumnDefinition Width="Auto"/>
                                            </Grid.ColumnDefinitions>
                                            <Grid.RowDefinitions>
                                                <RowDefinition Height="Auto"/>
                                                <RowDefinition Height="*"/>
                                                <RowDefinition Height="Auto"/>
                                            </Grid.RowDefinitions>
                                            <Button Command="{x:Static DataGrid.SelectAllCommand}" Focusable="false" Style="{DynamicResource {ComponentResourceKey ResourceId=DataGridSelectAllButtonStyle, TypeInTargetAssembly={x:Type DataGrid}}}" Visibility="{Binding HeadersVisibility, ConverterParameter={x:Static DataGridHeadersVisibility.All}, Converter={x:Static DataGrid.HeadersVisibilityConverter}, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}" Width="{Binding CellsPanelHorizontalOffset, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}"/>
                                            <DataGridColumnHeadersPresenter x:Name="PART_ColumnHeadersPresenter" Grid.Column="1" Visibility="{Binding HeadersVisibility, ConverterParameter={x:Static DataGridHeadersVisibility.Column}, Converter={x:Static DataGrid.HeadersVisibilityConverter}, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}"/>
                                            <ScrollContentPresenter x:Name="PART_ScrollContentPresenter" CanContentScroll="{TemplateBinding CanContentScroll}" Grid.ColumnSpan="2" Grid.Row="1"/>
                                            <ScrollBar x:Name="PART_VerticalScrollBar" Grid.Column="2" Maximum="{TemplateBinding ScrollableHeight}" Orientation="Vertical" Grid.Row="1" Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}" Value="{Binding VerticalOffset, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}" ViewportSize="{TemplateBinding ViewportHeight}"/>
                                            <Grid Grid.Column="1" Grid.Row="2">
                                                <Grid.ColumnDefinitions>
                                                    <ColumnDefinition Width="{Binding NonFrozenColumnsViewportHorizontalOffset, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}"/>
                                                    <ColumnDefinition Width="*"/>
                                                </Grid.ColumnDefinitions>
                                                <ScrollBar x:Name="PART_HorizontalScrollBar" Grid.Column="1" Maximum="{TemplateBinding ScrollableWidth}" Orientation="Horizontal" Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}" Value="{Binding HorizontalOffset, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}" ViewportSize="{TemplateBinding ViewportWidth}"/>
                                            </Grid>
                                        </Grid>
                                    </ControlTemplate>
                                </ScrollViewer.Template>
                                <ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
                            </ScrollViewer>
                        </Border>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
            <Style.Triggers>
                <MultiTrigger>
                    <MultiTrigger.Conditions>
                        <Condition Property="IsGrouping" Value="true"/>
                        <Condition Property="VirtualizingPanel.IsVirtualizingWhenGrouping" Value="false"/>
                    </MultiTrigger.Conditions>
                    <Setter Property="ScrollViewer.CanContentScroll" Value="false"/>
                </MultiTrigger>
            </Style.Triggers>
        </Style>

The button from the top left corner (above the row headers) is defined on this line:

    <Button Command="{x:Static DataGrid.SelectAllCommand}" Focusable="false"
            Style="{DynamicResource {ComponentResourceKey ResourceId=DataGridSelectAllButtonStyle, TypeInTargetAssembly={x:Type DataGrid}}}"
            Visibility="{Binding HeadersVisibility, ConverterParameter={x:Static DataGridHeadersVisibility.All}, Converter={x:Static DataGrid.HeadersVisibilityConverter}, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}"
            Width="{Binding CellsPanelHorizontalOffset, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}"/>

Accordingly, you can add processing in the following ways:

  1. Since this button receives the Style using DynamicResource, you can override or supplement this style by setting the required handler in it.

  2. You can set the CommandBinding for the SelectedAll command.

An example demonstrating both ways:

    <DataGrid>
        <UIElement.CommandBindings>
            <CommandBinding Command="{x:Static DataGrid.SelectAllCommand}"
                            CanExecute="OnSelectAllCanExecute"
                            Executed="OnSelectAllExecute"/>
        </UIElement.CommandBindings>
        <FrameworkElement.Resources>
            <Style x:Key="{ComponentResourceKey ResourceId=DataGridSelectAllButtonStyle, TypeInTargetAssembly={x:Type DataGrid}}"
                    TargetType="{x:Type Button}"
                    BasedOn="{StaticResource {ComponentResourceKey ResourceId=DataGridSelectAllButtonStyle, TypeInTargetAssembly={x:Type DataGrid}}}">
                <EventSetter Event="Click" Handler="OnClickSelectAll"/>
            </Style>
        </FrameworkElement.Resources>
        <DataGrid.Columns>
            <DataGridTextColumn Binding="{Binding Mode=OneWay}" Header="Letter"/>
        </DataGrid.Columns>
        <DataGrid.RowHeaderTemplate>
            <DataTemplate>
                <TextBlock Text="123456"/>
            </DataTemplate>
        </DataGrid.RowHeaderTemplate>
        <DataGrid.ItemsSource>
            <sys:String>123456</sys:String>
        </DataGrid.ItemsSource>
    </DataGrid>
        private void OnSelectAllCanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            e.CanExecute = true;
        }

        private void OnSelectAllExecute(object sender, ExecutedRoutedEventArgs e)
        {
            MessageBox.Show("The \"Select all\" command was invoked.");
        }

        private void OnClickSelectAll(object sender, RoutedEventArgs e)
        {
            MessageBox.Show("Was clicked \"Select all\".");
        }
Sign up to request clarification or add additional context in comments.

4 Comments

First of all: thanks for your detailed answer! I tried your sample but it did not work for me. I added the <FrameworkElement.Resources>...</FrameworkElement.Resources> part of your sample to my grid (with the click handler code of course).
Before I posted the code, I tested it on WPF Framework Win10. There shouldn't be any problems. I haven’t tested it on Core, but I don’t think that anything is different in this part. Write on which platform you are testing this code.
I use .NET 5 for my solution
I tested on Net5. As I expected, everything works exactly the same. You may have made some kind of copying error. Take the archive with my test code from here: drive.google.com/file/d/1Vq2GRG6Yqv_AUWOmG5Gbx4sKGQ1JdoCL/…

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.