1
votes

I need to be able to run a command on MouseDoubleClick event inside my DataGrid, however it seems that the event never makes it to the Grid due to the cell editing function that is started on a single click, even though I have a read only grid.

Here is an answer that talks about overriding the edit function on a winforms data grid, but I can't find the same on a windows controls data grid.

MouseDoubleClick event is not fired when a cell is double-clicked in System.Windows.Forms.DataGrid

I am fine with doing away with edit all together, altough I would like to keep it if possible. I do need to add edit capability in at some point, but it will only be activated by clicking on an edit button on each row, so if I need to have edit overwritten somehow I can just make the button open an overlay that allows them to enter the row values rather than entering them directly into the grid.

<DataGrid Grid.Row="1" Margin="0,0,0,0"  VerticalScrollBarVisibility="Auto" BorderBrush="{DynamicResource AccentColorBrush}" BorderThickness="1"
                                  HorizontalContentAlignment="Stretch" VerticalContentAlignment="Center" x:Name="AdvancedGrid" IsReadOnly="True"
                                  ItemsSource="{Binding FolderCollection, NotifyOnSourceUpdated=True}" SelectionMode="Extended"
                                  AutoGenerateColumns="False" CanUserDeleteRows="False" CanUserAddRows="False" CanUserResizeRows="True" 
                                  CanUserResizeColumns="True" CanUserSortColumns="True" CanUserReorderColumns="True" SelectedItem="{Binding LastSelectedItemAdvanced, Mode=TwoWay}"
                                    dataGridFilterLibrary:DataGridExtensions.ProcessIsInEditMode="True"

                                    dataGridFilterLibrary:DataGridExtensions.UseBackgroundWorkerForFiltering="True"

                                    dataGridFilterLibrary:DataGridExtensions.IsClearButtonVisible="False"

                                    dataGridFilterLibrary:DataGridExtensions.IsFilterVisible="True"

                                    ColumnHeaderStyle="{StaticResource {ComponentResourceKey 
                                            TypeInTargetAssembly={x:Type dataGridFilterLibrary:DataGridHeaderFilterControl}, 
                                            ResourceId=DataGridHeaderFilterControlStyle}}"
                                  >
            <i:Interaction.Triggers>
                <i:EventTrigger EventName="MouseDoubleClick">
                    <command:EventToCommand Command="{Binding OpenFolderCommand}" AlwaysInvokeCommand="True" CommandParameter="{Binding ElementName=SelectedItemBox, Path=SelectedItem}"/>
                </i:EventTrigger>
            </i:Interaction.Triggers>
        <DataGrid.Columns>
                <DataGridTextColumn Width="*" MinWidth="125" Header="Folder Name"
                                    Binding="{Binding Name}"
                                    >

                </DataGridTextColumn>
                <DataGridTemplateColumn>
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <TextBlock Text="{Binding Path=DataContext.Name, RelativeSource={RelativeSource Self}}"></TextBlock>
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
                </DataGridTemplateColumn>
            </DataGrid.Columns>
        </DataGrid>

SOLUTION UPDATE 04/12/18

I marked the answer below as best option (the only option as of now) since it brought me to my answer, which is very similar just a little less dirty.

While trying to figure out why the supplied solution doesn't encounter the same problem with the event not getting fired I noticed that it was using a style attached to the cell. So it seems that the DataGrid's mouse click can still be captured as long as you look for them inside the cell. Knowing that information there is no need to use the "PreviewMouseLeftButtonDown" with a dirty code behind method that counts clicks. If a "PreviewMouseLeftButtonDown" fires then a "PreviewMouseDoubleClick" event should fire as well.

XAML:

<DataGrid>
    <DataGrid.Resources>
        <Style TargetType="DataGridCell">
            <EventSetter Event="PreviewMouseDoubleClick" Handler="DataGridCell_PreviewMouseDoubleClick"></EventSetter>
        </Style>
    </DataGrid.Resources>
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="SelectionChanged" >
            <command:EventToCommand Command="{Binding UpdateSelectedItemsCommand, Mode=OneWay}" AlwaysInvokeCommand="True" CommandParameter="{Binding ElementName=FolderGrid, Path=SelectedItems}"  />
        </i:EventTrigger>
    </i:Interaction.Triggers>
    <DataGrid.Columns>
        <DataGridTextColumn Width="*" MinWidth="125" Header="Folder Name"
                                    Binding="{Binding Name}"
                                    >
        </DataGridTextColumn>
    </DataGrid.Columns>
</DataGrid>

Code Behind:

private async void DataGridCell_PreviewMouseDoubleClick(object sender, MouseButtonEventArgs e)
{
    var datacontext = this.DataContext as PublicFolderGridViewModel;

    if (datacontext?.LastSelectedFolder?.Identity != null)
    {
        await datacontext.LoadChildFoldersAsync(datacontext.LastSelectedFolder);
    }
}

On a side note, this is the only time I have had to create a code behind file for a view during this entire project. So this is the only code behind file, and the only thing in the code behind file is the double click handler. If anybody can show me how to implement this without a code behind using MVVM only please feel free to elaborate.

1

1 Answers

0
votes

This is a bit tricky since (as you have noticed) clicking in a datagrid already has a meaning. I think you're going to need some code. I put together an experiment to explore this. My code that works is:

 <DataGrid.Resources>
    <Style TargetType="DataGridCell">
        <EventSetter Event="PreviewMouseLeftButtonDown" Handler="DataGridCell_PreviewMouseLeftButtonDown"/>
    </Style>
</DataGrid.Resources>

and

private async void DataGridCell_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
    rowClickCount++;
    await Task.Delay(200);
    if (rowClickCount ==2)
    {
        rowClickCount = 0;
        MessageBox.Show("Invoke command");
    }
    rowClickCount = 0;
}

Which is of course a bit quick and dirty... but ok as a proof of concept. I get the messagebox up and by the time that fires, my row will be the current/selected row so I could invoke a command and rely on that to decide which item was double clicked.

If you want to apply that column by column you could do so by making that a style with a key and setting cellstyle on each column, roughly:

<DatagridTextColumn ..... CellStyle="{StaticResource doubleClickStyle}"