DataGridCheckboxColumn Fails to Trigger Row Edit Mode, Causing IEditableObject Methods to Be Skipped

In our app we have a page with SfDataGrid on it. The grid displays a list of stores and is also used for editing those stores. Store class that is a model for each row implements IEditableObject interface and has BeginEdit and EndEdit methods, the main use of these methods is to create a back up of a row before it is edited so that later you can cancell all changes to all the rows by falling back to the backup. The issue we encountered is that when you only use checkbox columns to edit a row the row doesn't enter into edit mode and BeginEdit, EndEdit methods are not invoked even though the changes to the model are applied anyway. (This doesn't occure if for example you first click on a DataGridTextColumn and then change checkboxes of the same row because in this case clicking on the DataGridTextColumn enters into edit mode and triggers BeginEditing so everything is handled as intended). So basically the problem is that clicking on a DataGridCheckboxColumn doesn't enter into edit mode.


The one workaround we found for that is to replace DataGridCheckboxColumn with DataGridTemplateColumn and use a regular checkbox with TapGestureRecognizer on it like this:

Image_9027_1718634307287


The reason we are using TapGestureRecognizer instead of CheckedChanged event is because when the DataGrid is created all checkboxes are unchecked and then the programm starts "manually" checking the once that should be changed thus triggering CheckedChanged event before the grid is even displayed.


Once the TapGesture is raised we handle the event by first reverting the value in the model to the opposite of what it was set to by the checkbox to make a snapshot of what the row looked like before the editing occured using BeginEdit method and then revert it back to save the changes.

Image_2168_1718634355541


I recreated a simpler version of this functionality in a separate project that I have attached here as well. Here is a brief description of the project, and a couple of steps you need to take to see what the problem is.


The model class Store is in the Store.cs file. The class countains a coulpe of fields, two events BeginEditingStore and StoreEdited. It also has BeginEdit method that calles OnBegginEditing method that in turn raises BeginEditingStore event. And similar EndEdit that calls OnBeginEdititng method that in turn raises the StoreEdited event.


The DataGrid is located on the MainPage.xaml, in its code behind there is a list of three stores, in the constructor AddStores method is called. It adds all stores to the list of rows after subscribing OnBeginEditing and OnStoreEdited methods from the code behind to BeginEditingStore and StoreEdited events of the Store object accordingly.


The ItemsSource property of the DataGrid is bound to Rows property that contains the list that is populated by AddStores in the constructor.


To see exactly what the porblem is, in the code behind (MainPage.xaml.cs) put a breakpoint in OnBeginEditing and OnStoreEdited methods and then lauch the project for Windows.

Image_6160_1718634256761

Image_3774_1718634501645

Once the app is running you will see two columns with checkboxes. The first one named "Active" is created using DataGridCheckboxColumn when you click on it neither OnBeginEditing nor OnStoreEdited will be invoked. The second column with checkboxes named "Main" is created using the workaround described before with a DataGridTemplateColumn that contains a regular checkbox with TapGestureRecognizer, as you can see by clicking on checkboxes from that column both OnBegginEditing and OnStoreEdited are hit. Another important thing to notice is that if you click on any of the text columns "Name" in this case the OnBegginEditing and OnStoreEdited will be invoked as well so this issue is specific to DataGridCheckboxColumns.


To sum up the problem, the core of the issue is that the DataGridCheckboxColumn does not automatically enter the row into edit mode upon interaction, which is necessary for the BeginEdit and EndEdit methods to be called.


Attachment: CheckboxTest_2111a8d8.zip

7 Replies

NY Nirmalkumar Yuvaraj Syncfusion Team June 18, 2024 01:54 PM UTC

Hi Vladimir


Upon analyzing the attached sample, it is clear that this is the expected behavior of the DataGridCheckBox column. The DataGridCheckBox column does not support the Editable property. You can utilize the workaround you shared. If this post is helpful, please consider Accepting it as the solution so that other members can locate it more quickly.


Regards,

Nirmalkumar.



AS Andrei Sbarnea June 18, 2024 02:18 PM UTC

Expected behavior is not what we hoped to hear, as the behavior is not consistent among different type of edit controls within the grid and therefore could not be intended as is, but only a result of bad design or lack of interest for a better design.



SD Sethupathy Devarajan Syncfusion Team June 19, 2024 02:26 PM UTC

Hi Andrei,

 

In SfDataGrid, BeginEdit and EndEdit events are called only the columns having different controls in UI and edit element. In CheckBox column, we have loaded the CheckBox as a UI control, so editing methods and events is not trigged for CheckBoxColumn. You can notify the editing operations of CheckBoxColumn by using DataGrid.CellValueChanged event.

this.dataGrid.CellValueChanged += DataGrid_CellValueChanged;

 

private void DataGrid_CellValueChanged(object? sender, DataGridCellValueChangedEventArgs e)

{

    // progress your work here.

}

 

Regards,

Sethupathy D.





VT Vladimir Turchanikov replied to Sethupathy Devarajan June 20, 2024 02:55 PM UTC

The problem with this approach as I indicated in my report is that clicking on a checkbox column and changing it is the same event. With any other type of column clicking the column and editing it are two different events, because of this we can invoke BeginEdit when a column is clicked and take a snapshot of the data in the row before it is edited.

With checkbox columns however once it was clicked the data changes immediately, this doesn't leave us any space to take a snapshot of the row before it was edited. This means that using CellValueChanged is not going to help, because it will be raised after the row had already been changed.



SD Sethupathy Devarajan Syncfusion Team June 21, 2024 11:34 AM UTC

Hi Vladimir,


Based on the provided information, it is clear that you need to take a snapshot of the DataRow before it is edited. We can achieve this by using a custom CheckBox renderer. I have shared both the code snippet and sample for your reference.


Code Snippet:

public partial class MainPage : ContentPage

{

     public MainPage()

     {

         InitializeComponent();

         this.dataGrid.CellRenderers.Remove("CheckBox");

         dataGrid.CellRenderers.Add("CheckBox", new DataGridCheckBoxCellRendererExt());

     }

}

 

public class DataGridCheckBoxCellRendererExt : DataGridCheckBoxCellRenderer

{

     protected override void OnInitializeDisplayView(DataColumnBase dataColumn, StackLayout? view)

     {

         base.OnInitializeDisplayView(dataColumn, view);

 

         if (view != null && view.Children[0] is CheckBox checkBox)

         {

             checkBox.PropertyChanging += DataGridCheckBoxCellRendererExt_PropertyChanging;

             checkBox.PropertyChanged += DataGridCheckBoxCellRendererExt_PropertyChanged;

         }

     }

 

     private void DataGridCheckBoxCellRendererExt_PropertyChanged(object? sender, System.ComponentModel.PropertyChangedEventArgs e)

     {

         if (e.PropertyName == "IsChecked")

         {

             Debug.WriteLine((sender as CheckBox)!.IsChecked);

         }

     }

 

     private void DataGridCheckBoxCellRendererExt_PropertyChanging(object sender, PropertyChangingEventArgs e)

     {

         if (e.PropertyName == "IsChecked")

         {

             // You can take your Snap here.

             Debug.WriteLine((sender as CheckBox)!.IsChecked);

         }

     }

}


Regards,

Sethupathy Devarajan.


Attachment: SfDataGridSample_38ca432c.zip


VT Vladimir Turchanikov replied to Sethupathy Devarajan July 1, 2024 12:25 PM UTC

Hi Sethupathy,

Thank you for your suggestion. Using a custom renderer solves part of the problem. Now focusing on a checkbox column and changing it are two different events which allows us to manually trigger BeginEdit and EndEdit at the correct moment. However, a couple of issues still remain. 

First of all  before the page is displayed what seems to happen is that  data grid is created with all checkbox columns unchecked and then, based on the underlying data, the program starts "manually" checking boxes that should be checked thus triggering DataGridCheckBoxCellRendererExt_PropertyChanging and populating our backup data with multiple snapshot of rows that the user didn't even interact with.

The second issue is that with this approach the checkbox column still stays disconnected from the state of the row, meaning that we should manually track if the row is already in edit mode when a checkbox is clicked. If we don't track the state what can happen is let's say a user first clicks on a text column, this enters the row into edit mode and BeginEdit is triggered taking a snapshot of the data, if after that a checkbox column of the same row is clicked and it is not being tracked weather or not the row is already in edit mode BeginEdit will be called again and incorrect snapshot will be taken, making it impossible to fully cancel changes later. The way we avoid having this problem now is by having IsInEditMode property on every Store and manually setting it when BeginEdit and EndEdit are called. This property is checked every time a checkbox is clicked which allows us to skip calling BeinEdit and EndEdit when the row is already in edit mode.


Image_7770_1719836511195



SD Sethupathy Devarajan Syncfusion Team July 2, 2024 12:15 PM UTC

Hi Vladimir,


Query

Response

    1. based on the underlying data, the program starts "manually" checking boxes that should be checked thus triggering DataGridCheckBoxCellRendererExt_PropertyChanging and populating our backup data with multiple snapshot of rows that the user didn't even interact with.

     

    1. The second issue is that with this approach the checkbox column still stays disconnected from the state of the row, meaning that we should manually track if the row is already in edit mode when a checkbox is clicked.

Based on the provided information, it is clear that DataGridCheckBoxCellRendererExt_PropertyChanging is triggered, populating your backup data with multiple snapshots of rows that the user didn't even interact with. You can restrict this with the IsFocused property of the checkbox.

 

Secondly, you had stated that the checkbox column still stays disconnected from the state of the row, causing manual tracking. You can get rid of manual tracking with the IsEditingItem property. We had shared the code snippet for your reference.

 

 

Code Snippet:

public class DataGridCheckBoxCellRendererExt : DataGridCheckBoxCellRenderer

{

    protected override void OnInitializeDisplayView(DataColumnBase dataColumn, StackLayout? view)

    {

        base.OnInitializeDisplayView(dataColumn, view);

 

        if (view != null && view.Children[0] is CheckBox checkBox)

        {

            checkBox.PropertyChanging += DataGridCheckBoxCellRendererExt_PropertyChanging;

            checkBox.PropertyChanged += DataGridCheckBoxCellRendererExt_PropertyChanged;

        }

    }

 

    private void DataGridCheckBoxCellRendererExt_PropertyChanged(object? sender, System.ComponentModel.PropertyChangedEventArgs e)

    {

        var checkBox = sender as CheckBox;

        if (e.PropertyName == "IsChecked" && checkBox != null && checkBox.IsFocused && !DataGrid!.View!.IsEditingItem)

        {

            Debug.WriteLine(checkBox.IsChecked);

        }

    }

 

    private void DataGridCheckBoxCellRendererExt_PropertyChanging(object sender, PropertyChangingEventArgs e)

    {

        var checkBox = sender as CheckBox;

        if (e.PropertyName == "IsChecked" && checkBox != null && checkBox.IsFocused && !DataGrid!.View!.IsEditingItem)

        {

            // You can take your Snap here.

            Debug.WriteLine(checkBox.IsChecked);

        }

    }

}


Regards,

Sethupathy Devarajan.


Loader.
Up arrow icon