Search code examples
c#wpfdatagridwpf-controlsdatagridcell

WPF DatagridTemplateColumn cell click event is not firing only if i click on the icon of the cell


I have a datagrid in WPF with some TextColumns and a TemplateColumn. These have different styles. Each TextColumn has the same BasicCell style with a click event which works fine if you click on one of the cells of the column. The TemplateColumn has TemplateColumnCell style. It contains a MaterialDesign icon and it looks like this:

<DataGridTemplateColumn Header="Edit"  Width="0.5*" CellStyle="{StaticResource TemplateColumnCell}">
     <DataGridTemplateColumn.CellTemplate>
          <DataTemplate>
              <materialDesign:PackIcon Kind="Edit" Width="15" HorizontalAlignment="Stretch"/>
           </DataTemplate>
     </DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>

The cell style of this template column, contains an EventSetter of PreviewMouseLeftButtonDown, but it fires only when the icon is clicked. I want it to fire when you click on the cell, not necessarily on the icon.

<Style x:Key="TemplateColumnCell"
           TargetType="{x:Type DataGridCell}">

        <Style.Triggers>
            <Trigger Property="IsSelected" Value="True">
                <Setter Property="Background" Value="Gainsboro"/>
                <Setter Property="Foreground" Value="Black"/>
                <Setter Property="BorderThickness" Value="0"/>
            </Trigger>

            <DataTrigger Binding="{Binding IsEnabled}" Value="False">
                <Setter Property="IsEnabled" Value="True"/>
                <Setter Property="Foreground" Value="LightSlateGray"/>
            </DataTrigger>
        </Style.Triggers>
        
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type DataGridCell}">
                    <Border Padding="{TemplateBinding Padding}" SnapsToDevicePixels="True">
                        <ContentPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
        
        <EventSetter Event="PreviewMouseLeftButtonDown" 
                     Handler="myTemplateCell_PreviewMouseDown"/>
    </Style>

Why isn't this working? And what could I do to make it work?


Solution

  • To enable the complete cell to receive mouse interaction you must either add a container to the template that spans over the complete cell or override the ControlTemplate properly. Properly in this case means that you must set the Border.Background to Transparent in order to make it hit test visible.
    An adequate container to host the content of a cell could be a Border or a Grid or anything that naturally stretches to occupy the full available space. The examples below use a Border.

    Note that it is sufficient to set SnapsToDevicePixels on the parent element as it will be inherited. Therefore, if you set it on the root of the tree (e.g. Window.SnapsToDevicePixels), then the complete Window and all its child elements will inherit the value.

    Solution 1

    Modify your column's cell template:

    <DataGridTemplateColumn.CellTemplate>
        <DataTemplate>
          <Border Background="Transparent">
            <materialDesign:PackIcon Kind="Edit" 
                                     Width="15" 
                                     HorizontalAlignment="Stretch"/>
          </Border>
        </DataTemplate>
    </DataGridTemplateColumn.CellTemplate>
    </DataGridTemplateColumn>
    

    Solution 2

    Modify your cell template (from your cell Style):

    <Style x:Key="TemplateColumnCell"
           TargetType="{x:Type DataGridCell}">
    
      ...
    
      <Setter Property="Template">
        <Setter.Value>
          <ControlTemplate TargetType="{x:Type DataGridCell}">
            <Border Background="Transparent">
              <ContentPresenter />
            </Border>
          </ControlTemplate>
        </Setter.Value>
      </Setter>
    </Style>