0

I have a DataGrid with CheckBox-type column which should be editable with single click. This is easily achieved by using template column with CheckBox inside:

<DataGridTemplateColumn.CellTemplate>
    <DataTemplate>
        <CheckBox IsChecked="{Binding Path=IsSelected, UpdateSourceTrigger=PropertyChanged}" />
    </DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
    <DataTemplate>
        <CheckBox BackGround="Red" IsChecked="{Binding Path=IsSelected, UpdateSourceTrigger=PropertyChanged}" />
    </DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>

the problem, however, is that single clicking will change the value without ever entering Edit mode. How can I ensure the edit mode is entered before changing the CheckBox value (all will single click)?


My best attempt on the problem was setting PreviewMouseLeftButtonDown on DataGridCell through style and forcing BeginEdit(). While this does begin edit, it is back to needing double click to interact.

private void DataGridCell_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
    if (sender is DataGridCell cell && !cell.IsEditing && e.OriginalSource is DependencyObject source)
    {
        var checkBoxParent = VisualExtensions.GetVisualParent<CheckBox>(source);
        if (checkBoxParent != null) // ensure CheckBox was clicked
        {
            cell.Focus();
            ItemListDG.BeginEdit();
        }
    }
}

I have also tried handling Selected or GotFocus without any luck (breaks other types of interaction), CheckBox.Checked events cannot be used neither because they trigger on re/load.


In case of Selected event, the problem is that it enables single click edit on all columns even though it is handled on just one column (again, set through style):

private void DataGridCell_Selected(object sender, RoutedEventArgs e)
{
    // second part of condition is always true, no matter what cell is clicked
    if (sender is DataGridCell cell && cell.Column == ItemListDG.Columns[0])
    {
        // try to detect if the CheckBox column was clicked, if not return
        if (sender != e.OriginalSource) // always false
            return;

        ItemListDG.BeginEdit(e); // always executes no matter the source
    }
}
wondra
  • 3,271
  • 3
  • 29
  • 48
  • The control in the `CellTemplate` is not visibile when you're in edit mode. This is supposed to be a read-only control. Did you see [this](https://stackoverflow.com/questions/3426765/single-click-edit-in-wpf-datagrid)? – mm8 Nov 10 '20 at 14:13
  • @mm8 yes, I have seen it and tried handling `Selected` event, it breaks other types of interaction. In the case of `Selected` it is global, even if you attach it to just one column, it fires when clicking other columns as well, causing single click edit on every single one column. – wondra Nov 10 '20 at 14:29
  • You could determine which column is clicked using the `Column` property of the `DataGridCell`. – mm8 Nov 10 '20 at 14:31
  • @mm8 that was one of my ideas as well, turns out the event args do not have the actual Source/OriginalSource/sender information, all three are set to the `DataGridCell` on which `Selected` is attached on, regardless what cell was clicked. – wondra Nov 10 '20 at 14:33
  • `DataGridCell` is the cell that was clicked, isn't it? Please provide an example of where you failed. – mm8 Nov 10 '20 at 14:34
  • @mm8 sure, got a bunch more failed attempts, added the one with `Selected` with annotations. – wondra Nov 10 '20 at 14:39
  • So why don't you use the `Column` property as I suggested? `sender is DataGridCell cell && cell.Column == yourColumn...` – mm8 Nov 10 '20 at 14:41
  • @mm8 let me rephrase, the cell of `Selected` event is not being set by WPF correctly. No matter what, it is the cell the event is on, not the actually selected/clicked cell. The `sender is DataGridCell cell && cell.Column == yourColumn` always evaluates to `true`, – wondra Nov 10 '20 at 14:49
  • No, it doesn't. What is `yourcolumn` in your case? – mm8 Nov 10 '20 at 14:52
  • @mm8 first column (`ItemListDG.Columns[0]`), updated the sample with the column comparison code. It is always true, always edits on click, the event is attached only on the first column cells. – wondra Nov 10 '20 at 14:56
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/224369/discussion-between-wondra-and-mm8). – wondra Nov 10 '20 at 14:56

1 Answers1

0

The event which should be handled is PreviewMouseLeftButtonUp, same like the case with Down event, after BeginEdit() is called the original CheckBox does not exist anymore and cannot handle the un/checking. The solution to doubleclick problem is to find the new representation of the CheckBox and either re-raise the event threre or toggle it manually:

private void DataGridCell_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
    if (sender is DataGridCell cell && !cell.IsEditing && e.OriginalSource is UIElement source)
    {
        var actualSource = source is CheckBox ? 
            (CheckBox)source : VisualExtensions.GetVisualParent<CheckBox>(source);

        if (actualSource != null)
        {
            ItemListDG.BeginEdit();

            var newSource = cell.GetVisualChild<CheckBox>();
            if (newSource != null)
            {
                newSource.IsChecked = !newSource.IsChecked;
            }
        }      

    }
}
wondra
  • 3,271
  • 3
  • 29
  • 48