Search code examples
c#wpfdatatemplate

DoubleClick fired both in DataGrid and DataTemplate


Long story short; I have a grid inside a grid. Both grids have double click events that are supposed to fire different method calls (the main grid shows a window while the grid in the DataTemplate shows a window with parameters from the selected detail row).

The problem is that double clicking in the detail row also calls the double click on the main grid even though e.Handled is set to true.

The dumbed down XAML:

<Window x:Class="DoubleClickDataTemplate.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:DoubleClickDataTemplate"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Window.Resources>
        <DataTemplate x:Key="LinesGrid">
            <DataGrid x:Name="dgLines" 
                        ItemsSource="{Binding Path=Lines}" 
                        AutoGenerateColumns="True" 
                        IsReadOnly="True"
                        MouseDoubleClick="dgLines_MouseDoubleClick">
            </DataGrid>
        </DataTemplate>
    </Window.Resources>
    <Grid>
        <DataGrid x:Name="dgFiles" 
                    ItemsSource="{Binding}" 
                    AutoGenerateColumns="True" 
                    IsReadOnly="True"
                    RowDetailsVisibilityMode="VisibleWhenSelected"
                    RowDetailsTemplate="{StaticResource LinesGrid}" 
                    MouseDoubleClick="dgFiles_MouseDoubleClick">
        </DataGrid>
    </Grid>
</Window>

The dumbed down source file:

using System.Collections.Generic;
using System.Windows;
using System.Windows.Input;

namespace DoubleClickDataTemplate
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            List<FileClass> files = new List<FileClass>();
            files.Add(new FileClass() { FileName = "File1", Lines = new List<LineClass>() { new LineClass() { LineNumber = 1, LineContents = "F1L1 contents" }, new LineClass() { LineNumber = 2, LineContents = "F1L2 contents" } } });
            files.Add(new FileClass() { FileName = "File2", Lines = new List<LineClass>() { new LineClass() { LineNumber = 1, LineContents = "F2L1 contents" }, new LineClass() { LineNumber = 2, LineContents = "F2L2 contents" } } });
            dgFiles.ItemsSource = files;
        }

        private void dgFiles_MouseDoubleClick(object sender, MouseButtonEventArgs e)
        {
            System.Diagnostics.Debug.WriteLine("dgFiles_MouseDoubleClick(object sender, MouseButtonEventArgs e)");
        }

        private void dgLines_MouseDoubleClick(object sender, MouseButtonEventArgs e)
        {
            System.Diagnostics.Debug.WriteLine("dgLines_MouseDoubleClick(object sender, MouseButtonEventArgs e)");
            e.Handled = true;
        }
    }

    public class FileClass
    {
        public string FileName { get; set; }
        public List<LineClass> Lines { get; set; }
    }

    public class LineClass
    {
        public int LineNumber { get; set; }
        public string LineContents { get; set; }
    }
}

The output shows that both events gets called when I double click in the DataTemplate/DetailRow:

00:05.616 (00:03:456) dgLines_MouseDoubleClick(object sender, MouseButtonEventArgs e)
                      dgFiles_MouseDoubleClick(object sender, MouseButtonEventArgs e)

The closest got to a "solution" was using a lock flag (https://www.oipapio.com/question-3430969), but that can go wrong in too many ways.

Is there a way to make double clicking on the detail row only call the relevant event instead of both events?


Solution

  • You could handle the MouseLeftButtonDown and check the ClickCount for the outer DataGrid:

    private void dgFiles_MouseDoubleClick(object sender, MouseButtonEventArgs e)
    {
        if (e.ClickCount == 2)
        {
            System.Diagnostics.Debug.WriteLine("dgFiles_MouseDoubleClick(object sender, MouseButtonEventArgs e)");
        }
    }
    
    
    private void dgLines_MouseDoubleClick(object sender, MouseButtonEventArgs e)
    {
        System.Diagnostics.Debug.WriteLine("dgLines_MouseDoubleClick(object sender, MouseButtonEventArgs e)");
        e.Handled = true;
    }
    

    XAML:

    <Window.Resources>
        <DataTemplate x:Key="LinesGrid">
            <DataGrid x:Name="dgLines" 
                    ItemsSource="{Binding Path=Lines}" 
                    AutoGenerateColumns="True" 
                    IsReadOnly="True"
                    MouseDoubleClick="dgLines_MouseDoubleClick">
            </DataGrid>
        </DataTemplate>
    </Window.Resources>
    <Grid>
        <DataGrid x:Name="dgFiles" 
                ItemsSource="{Binding}" 
                AutoGenerateColumns="True" 
                IsReadOnly="True"
                RowDetailsVisibilityMode="VisibleWhenSelected"
                RowDetailsTemplate="{StaticResource LinesGrid}" 
                MouseLeftButtonDown="dgFiles_MouseDoubleClick">
        </DataGrid>
    </Grid>