Completed
Last Updated: 27 Mar 2023 06:39 by ADMIN
Release R1 2023 SP1
Martin
Created on: 13 Jan 2023 12:37
Category: UI for WinForms
Type: Bug Report
1
Cut method of RadVirtualGrid deletes rows prematurely.

The Cut operations of the RadVirtualGrid does not work.

When the SelectionMode is set to FullRowSelect, MultiSelect = true, and multiple rows are selected, the loop goes something like this:

// Pseudo code:
for(int rowIndex = firstRow; rowIndex <= lastRow; rowIndex++)
{
    AddRowToClipboardData(rowIndex)
    UserDeletedRow(rowIndex);
}
What is wrong here?
  1. Lets say 10 rows are selected, only the even rows get copied. First row 0 is copied and deleted. When row 0 is deleted, all rows move a position down. So when copying row 1, it is actually row 2 that is copyied.
  2. When cutting all rows, in my case an exception is thrown, because a rowIndex larger than the number of rows is referred to.
  3. When cutting to multiple clipboard formats, the second format will not contain the original selected data, because it has already been deleted.

My suggestion:

  1. First copy all the data and formats to the clipboard.
  2. Then delete the selected rows.

 

5 comments
ADMIN
Dinko | Tech Support Engineer
Posted on: 23 Jan 2023 12:09

Hello Martin,

Thank you for the provided details.

Upon checking again the mentioned CSV section in the application you are right there is still a difference even after the workaround. I will also mention this in the internal backlog item so that the development team will take this into account when starts working on the item.

Regards,
Dinko | Tech Support Engineer
Progress Telerik

Love the Telerik and Kendo UI products and believe more people should try them? Invite a fellow developer to become a Progress customer and each of you can get a $50 Amazon gift voucher.

Martin
Posted on: 20 Jan 2023 10:08

Hi Dinko,

The Text-format on the clipboard is now correctly filled. The CSV-format on the clipboard is empty (it contains only the CR+LF for each row), which should contain the same values.

I think my suggestion is stel best:

  1. First copy all the data and formats to the clipboard.
  2. Then delete the selected rows.

ADMIN
Dinko | Tech Support Engineer
Posted on: 19 Jan 2023 12:33

Hello Martin,

Thank you for the provided details.

I was able to observe the described behavior. This behavior comes from the fact that when you perform a cut operation, the UserDeletedRow event will be called for each cut row. This approach in a multi-select scenario won't be valid. Because, when you delete a row,  the event will be called on each row. The row index won't be valid at a certain point which leads to the exception. This is also the result of the second bug. When you delete a row, CellValueNeeded will be called to get the new value but this row index is already replaced with the next one in the DataTable. That is why it seems that the cut operation only gets the event values. The general approach here is to call the UserDeleteRow in a multi-select scenario when Cut/Copy operation is executed. This needs to be handled internally. Therefore I will approve the feedback item and forward this to our development team.

After trying different approaches I think I was able to find a way to delete the rows properly. I have modified the _grid_UserDeletedRow event handler. You can check the attached project. I can agree the workaround is not pretty but there were a lot of scenarios that need to be handled. For example, selecting rows at the beginning and at the end of the collection. You can try it and modified to fit your application. 

As for not synchronizing the control after CUT, you were right. The grid does not consider the cut operation for an update. I have logged this in a separate feedback item on your behalf. The above approach also includes a workaround for this. You can use the DeleteRow() method of the control to force its update and delete the rows.

As a side note, the code is located in the TestForm.cs file.

I have updated your Telerik Points for both behaviors.

Regards,
Dinko | Tech Support Engineer
Progress Telerik

Love the Telerik and Kendo UI products and believe more people should try them? Invite a fellow developer to become a Progress customer and each of you can get a $50 Amazon gift voucher.

Martin
Posted on: 17 Jan 2023 13:13

Here is my example code.

With this you can create multiple bugs:

Bug 1:

  1. Select all
  2. Cut
  3. Observed: The grid will crash
    Expected: No crash

Bug 2:

  1. Download Free Clipboard Viewer
  2. Select values 0 till 5.
  3. Cut
  4. In Clipboard Viewer you will see:
    1. Text: 0 2 4 6 8 10 (Expected: 0, 1, 2, 3, 4, 5)
    2. CSV: 1 5 9 12 14 16 (Expected: 0, 1, 2, 3, 4, 5)
  5. Also:
    Observed: The grid is not synchronized.
    Expected: That grid is synchronized.

 

The code:

 

using System.Data;
using System.Linq;
using System.Windows.Forms;
using Telerik.WinControls.UI;

namespace Turien.Schade.PremiumCalculator.TestForms
{
public partial class TestForm : Form
{
private readonly DataView _view;

public TestForm()
{
InitializeComponent();
_view = new DataView(LoadTable());
_grid.ColumnCount = _view.Table.Columns.Count;
_grid.RowCount = _view.Count;
}

static private DataTable LoadTable()
{
var table = new DataTable();
table.Columns.Add("Number", typeof(int));
for (int i = 0; i < 20; i++)
table.Rows.Add(i);
return table;
}


#region Windows Form Designer generated code

/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this._grid = new Telerik.WinControls.UI.RadVirtualGrid();
((System.ComponentModel.ISupportInitialize)(this._grid)).BeginInit();
this.SuspendLayout();
// 
// _grid
// 
this._grid.Dock = System.Windows.Forms.DockStyle.Fill;
this._grid.Location = new System.Drawing.Point(0, 0);
this._grid.MultiSelect = true;
this._grid.Name = "_grid";
this._grid.SelectionMode = Telerik.WinControls.UI.VirtualGridSelectionMode.FullRowSelect;
this._grid.Size = new System.Drawing.Size(800, 450);
this._grid.TabIndex = 0;
this._grid.CellValueNeeded += new Telerik.WinControls.UI.VirtualGridCellValueNeededEventHandler(this._grid_CellValueNeeded);
this._grid.UserDeletedRow += new Telerik.WinControls.UI.VirtualGridRowsEventHandler(this._grid_UserDeletedRow);
// 
// TestForm
// 
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(800, 450);
this.Controls.Add(this._grid);
this.Name = "TestForm";
this.Text = "TestForm";
((System.ComponentModel.ISupportInitialize)(this._grid)).EndInit();
this.ResumeLayout(false);

}

#endregion

private Telerik.WinControls.UI.RadVirtualGrid _grid;

private void _grid_CellValueNeeded(object sender, Telerik.WinControls.UI.VirtualGridCellValueNeededEventArgs e)
{
if (e.ColumnIndex < 0) 
return;

if (e.RowIndex < 0)
{
e.FieldName = _view.Table.Columns[e.ColumnIndex].ColumnName;
if (e.RowIndex == RadVirtualGrid.HeaderRowIndex)
e.Value = e.FieldName;
}
else
{
e.Value = _view[e.RowIndex][e.ColumnIndex];
}
}

private void _grid_UserDeletedRow(object sender, Telerik.WinControls.UI.VirtualGridRowsEventArgs e)
{
var rowIndexes = e.RowIndices.Distinct().OrderByDescending(i => i).ToList(); // Off topic: I have seen duplicate row indexes in this row collection. And unsorted. Is that by design?
if (rowIndexes.Count == _view.Count)
{
_view.Table.Rows.Clear();
}
else
{
foreach (var index in rowIndexes)
_view[index].Delete();
}
}
}
}
ADMIN
Dinko | Tech Support Engineer
Posted on: 17 Jan 2023 09:16

Hi Martin,

Thank you for the provided steps. 

Before proceeding to the reported behavior I need to clarify the cut operation inside the RadGridView. When the user tries to cut some cells inside the control, the developer needs to handle this case to assure that the cut value is correctly transferred to the data source. What does mean? In this case, the CellValuePushed will be called in Ctrl+X key combination in which the e.Value from the event arguments will be null and need to replace the correct object value from the data source collection. Afterward, the CellValueNeeded event is triggered, where you update the grid cut cell values from the collection. 

As for the reported scenario, I wasn't able to completely reproduce these behaviors. To be on the same page, may I ask you to modify my test project attached here to mimic your implementation and send it back? In the process of investigating your scenarios, I have hit different behavior with the cells not updating properly when the cut operation is executed. However, the rows are not deleted on my side nor do exceptions occur. Also, I need to see how the format is applied in your application.

I am looking forward to the updated project so I can debug it on my side.

Thank you again for your dedication in reporting this and sharing your suggestions.

Regards,
Dinko | Tech Support Engineer
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/.

Attached Files: