Unplanned
Last Updated: 17 Apr 2024 14:40 by ADMIN
Martin
Created on: 27 Jul 2022 13:52
Category: UI for WinForms
Type: Bug Report
0
Selecting one cell automatically selects another due to same HashCodeString.

Repro-steps:

  1. Create a RadGridView
  2. MultiSelect = true
  3. SelectionMode = CellSelect
  4. Fill it with lots of cells (in my case: 7 columns, 8544 rows)
  5. Press CTRL-A
  6. Press Delete

Expected behavior:

  • All rows are gone

Observed behavior:

  • 50/50 change that some rows remain.

I traced the problem back to the method GridViewSleectedCellsCollection.IsSelected / GetHashCodeString.

internal bool IsSelected(GridViewRowInfo row, GridViewColumn column) => row != null && column is GridViewDataColumn && this.hashtable.Contains((object) this.GetHashCodeString(row, column));

When a cell is selected with GridViewCellInfo.IsSelected = true, it checks if it has already been selected. It does so by calling GridViewSleectedCellsCollection.IsSelected. which checks if a HasCodeString is already in a hashtable. But, when another selected cell has the same HasCodeString, the result is (incorrectly) true, which will result in not added it to the collection of selected cells. 

I guess that is can be easily fixed by changing:

 private string GetHashCodeString(GridViewRowInfo row, GridViewColumn column)
    {
      int hashCode = row.GetHashCode();
      string str1 = hashCode.ToString();
      hashCode = column.GetHashCode();
      string str2 = hashCode.ToString();
      return str1 + str2;
    }

to:

 private string GetHashCodeString(GridViewRowInfo row, GridViewColumn column)
    {
      int hashCode = row.GetHashCode();
      string str1 = hashCode.ToString();
      hashCode = column.GetHashCode();
      string str2 = hashCode.ToString();
      return str1 + "_" + str2;
    }

Since hashcodes 1 + 23 will result in the same string as hashcodes 12 + 3.

Making this change will reduce the problem significantly, but not entirely since hashCodes will never be unique.

1 comment
ADMIN
Dinko | Tech Support Engineer
Posted on: 29 Jul 2022 12:58

Hi Martin,

Thank you for the provided detailed steps.

I have followed your steps and you are right that on some occasions selecting all rows and delete is pressed will not delete all rows. I have forwarded this to our development team so that they could consider this in their planning. In the meantime, I can confirm that this behavior is unexpected and change the status of the item to Unplanned. Your Telerik Points are updated for bringing this behavior to our attention.

As a workaround, you can handle this case in code. What you can do is create a custom GridDataRowBehavior. Inside the custom class, you could override the ProcessKey method. here you can check if the Ctrl+A and Delete key is used. If the first combination is used raise a flag which later you could check. If such a flag exists call the Rows.Clear() method. Below you could find a sample code that demonstrates this approach.

public class CustomDataRowBehavior: GridDataRowBehavior
{
    public static bool IsControlDown()
    {
        return (Control.ModifierKeys & Keys.Control) == Keys.Control;
    }

    public override bool ProcessKey(KeyEventArgs keys)
    {
        if (this.GridControl.Tag != null && this.GridControl.Tag.ToString() == "SelectAll" && keys.KeyCode == Keys.Delete)
        {
            this.GridControl.Rows.Clear();
            this.GridControl.Tag = null;
            return true;
        }
        base.ProcessKey(keys);
        if (IsControlDown() && keys.KeyCode == Keys.A)
        {
            this.GridControl.Tag = "SelectAll";
            return true;
        }
            
        return true;
    }
}


public RadForm1()
{
	InitializeComponent();
	this.radGridView1.MultiSelect = true;
	BaseGridBehavior gridBehavior = radGridView1.GridBehavior as BaseGridBehavior;
	gridBehavior.UnregisterBehavior(typeof(GridViewDataRowInfo));
	gridBehavior.RegisterBehavior(typeof(GridViewDataRowInfo), new CustomDataRowBehavior());
	this.radGridView1.SelectionMode = GridViewSelectionMode.CellSelect;
	this.radGridView1.SelectionChanged += RadGridView1_SelectionChanged;	
}

private void RadGridView1_SelectionChanged(object sender, EventArgs e)
{
	this.radGridView1.Tag = null;
}

I hope this approach will work for you.

Regards,
Dinko
Progress Telerik

Virtual Classroom, the free self-paced technical training that gets you up to speed with Telerik and Kendo UI products quickly just got a fresh new look + new and improved content including a brand new Blazor course! Check it out at https://learn.telerik.com/.