- Add a row called "Telerik.Hello", filter for contains "Telerik" - no rows displayed - Add some rows some of which empty, filter does not contain "some string", the empty rows are removed, while they should remain
To reproduce:
- use the code below to create an application
- start it and click the Id column twice (so you will sort it first ascending and then descending)
- double click the first row (with ID=9) => the BindingList current is still the row with ID 0, while it should be the row with ID 9
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
SetDefaults();
}
private void SetDefaults()
{
radGridView1.MasterTemplate.AutoGenerateColumns = false;
radGridView1.MasterTemplate.AutoSizeColumnsMode = GridViewAutoSizeColumnsMode.None;
radGridView1.MasterTemplate.EnableAlternatingRowColor = true;
radGridView1.TableElement.AlternatingRowColor = Color.FromArgb(0xEB, 0xEF, 0xFB);
radGridView1.MasterTemplate.ShowGroupedColumns = true;
radGridView1.MasterTemplate.EnableGrouping = true;
radGridView1.MasterTemplate.MultiSelect = false;
radGridView1.EnableFiltering = true;
radGridView1.EnableFastScrolling = true;
radGridView1.TableElement.TableHeaderHeight = 50;
}
private void Form1_Load(object sender, EventArgs e)
{
var users = new EmployeeList();
for (int i = 0; i < 10; i++)
{
var user = new Employee();
user.Id = i;
user.Name = "John Doe " + i;
users.Add(user);
}
employeeListBindingSource.DataSource = users;
}
private void radGridView1_CellDoubleClick(object sender, Telerik.WinControls.UI.GridViewCellEventArgs e)
{
if (e.RowIndex == -1 || e.Row.RowElementType != typeof(GridDataRowElement) || !(e.Row is GridViewDataRowInfo))
return;
var selectedUser = employeeListBindingSource.Current as Employee;
MessageBox.Show(selectedUser.Name);
}
}
public class Employee
{
public int Id { get; set; }
public string Name { get; set; }
public Employee()
{
}
}
public class EmployeeList : BindingList<Employee>
{
public EmployeeList()
{
}
}
To reproduce - Have a page view with two pages - one empty and one with a grid - put some cell in the grid in edit mode and cancel its validation in the CellValidating event - at this point you cannot change the current cell in the grid (which is desired) but you are able to switch to another page in the page view, thus its SelectedPageChanging event fires (which is not desired)
ADD. RadGridView - add row selection with Space in MultiSelection mode Notice: This functionality works only in multiselection and EditMode different than RadGridViewBeginEditMode.BeginEditOnKeystrokeOrF2 RadGridViewBeginEditMode.BeginEditOnKeystroke
When the DataType of the column is not a floating point number, decimals should not be displayed. This should affect both the excel like filtering and the regular filtering
ADD. RadGridView should support binding to IQuerable
ADD. RadGridView - add kitetic scrolling support
Steps to reproduce:
1. Drag a RadGridView to a form
2. Add a text column and a hyperlink column
3. Add a row with null value for the hyperlink cell
4. Set some text for the hyperlink cell
5. Subscribe to the HyperlinkOpening/ed events
6. Run the project and click on the hyperlink, you will see that none of the events will be fired.
Workaround:
To work around it, you can create your own cell element which derives from the GridHyperlinkCellElement and override the ProcessHyperlink method to handle the user clicking on a hyperlink:
public class MyHyperlinkCellElement : GridHyperlinkCellElement
{
public MyHyperlinkCellElement(GridViewColumn col, GridRowElement row)
: base(col, row)
{ }
protected override void ProcessHyperlink()
{
//handle hyperlink click
}
}
After you have created your cell element, you can replace the original using the CreateCell event of the RadGridView:
private void radGridView1_CreateCell(object sender, GridViewCreateCellEventArgs e)
{
if (e.Column is GridViewHyperlinkColumn)
{
e.CellType = typeof(MyHyperlinkCellElement);
}
}
The following HTMLViewDefinition has a wrong layout when run:
HtmlViewDefinition view = new HtmlViewDefinition();
view.RowTemplate.Rows.Add(new RowDefinition());
view.RowTemplate.Rows.Add(new RowDefinition());
view.RowTemplate.Rows.Add(new RowDefinition());
view.RowTemplate.Rows[0].Cells.Add(new CellDefinition("column0", 0, 1, 1));
view.RowTemplate.Rows[0].Cells.Add(new CellDefinition("column1", 0, 1, 3));
view.RowTemplate.Rows[0].Cells.Add(new CellDefinition("column2", 0, 1, 1));
view.RowTemplate.Rows[1].Cells.Add(new CellDefinition("column3", 0, 1, 2));
view.RowTemplate.Rows[1].Cells.Add(new CellDefinition("column4", 0, 1, 1));
view.RowTemplate.Rows[2].Cells.Add(new CellDefinition("column5", 0, 1, 1));
The layout puts column5 over column1.
A possible workaround would be to refresh the rows in the grid's SizeChanged event handler:
private void RadGridView1_SizeChanged(object sender, EventArgs e)
{
radGridView1.TableElement.ViewElement.UpdateRows(true);
}
Steps to reproduce:
1. expand a parent row
2. remove the first child row (e.g. 'Jon Smith') by selecting the child row and press the button at the top
3. remove the second (last) child row (in this case 'Pete van Dijk') the same way
Here is the code snippet:
public partial class Form1 : Form
{
private List<Department> _departments;
public Form1()
{
InitializeComponent();
SetGridParentColumns();
SetGridChildTemplate();
InitData();
grid.RowSourceNeeded += grid_RowSourceNeeded;
}
private void InitData()
{
_departments = new List<Department>(2);
Department dep1 = new Department() { DepartmentId = 1, Name = "Accounting" };
Department dep2 = new Department() { DepartmentId = 2, Name = "Finance" };
Employee emp1 = new Employee() { DepartmentId = 1, EmployeeId = 1, FirsName = "John", LastName = "Smith" };
Employee emp2 = new Employee() { DepartmentId = 1, EmployeeId = 2, FirsName = "Pete", LastName = "van Dijk" };
Employee emp3 = new Employee() { DepartmentId = 2, EmployeeId = 3, FirsName = "Mark", LastName = "Smith" };
Employee emp4 = new Employee() { DepartmentId = 2, EmployeeId = 4, FirsName = "Jan", LastName = "Janssen" };
dep1.Employees = new List<Employee>() { emp1, emp2 };
dep2.Employees = new List<Employee>() { emp3, emp4 };
_departments.Add(dep1);
_departments.Add(dep2);
grid.DataSource = _departments;
grid.AllowAddNewRow = false;
grid.BestFitColumns();
}
private void SetGridParentColumns()
{
grid.AutoGenerateColumns = false;
grid.Columns.Add("DepartmentId", "DepartmentId", "DepartmentId");
grid.Columns.Add("Name", "Name", "Name");
}
private void SetGridChildTemplate()
{
grid.Templates.Clear();
GridViewTemplate childTemplate = new GridViewTemplate();
childTemplate.Columns.Add("EmployeeId");
childTemplate.Columns.Add("DepartmentId");
childTemplate.Columns.Add("FirstName");
childTemplate.Columns.Add("LastName");
grid.Templates.Add(childTemplate);
childTemplate.HierarchyDataProvider = new GridViewEventDataProvider(childTemplate);
}
private void grid_RowSourceNeeded(object sender, GridViewRowSourceNeededEventArgs e)
{
Department dep = e.ParentRow.DataBoundItem as Department;
foreach (Employee employee in dep.Employees)
{
GridViewRowInfo gridRow = e.Template.Rows.NewRow();
gridRow.Cells["EmployeeId"].Value = employee.EmployeeId;
gridRow.Cells["DepartmentId"].Value = employee.DepartmentId;
gridRow.Cells["FirstName"].Value = employee.FirsName;
gridRow.Cells["LastName"].Value = employee.LastName;
e.SourceCollection.Add(gridRow);
}
e.Template.AllowAddNewRow = false;
e.Template.BestFitColumns();
}
private void btnRemoveChildRow_Click(object sender, EventArgs e)
{
GridViewRowInfo row = grid.SelectedRows[0];
if (row.ViewTemplate.Parent == null)
return; //department (parent) row, so don't remove it
int employeeId = Convert.ToInt32(row.Cells["EmployeeId"].Value);
int departmentId = Convert.ToInt32(row.Cells["DepartmentId"].Value);
Department dep = GetDepartment(departmentId);
dep.RemoveEmployee(employeeId);
row.ViewTemplate.Refresh();
}
private Department GetDepartment(int departmentId)
{
foreach (Department dep in _departments)
if (dep.DepartmentId == departmentId)
return dep;
return null;
}
}
public class Department
{
public int DepartmentId { get; set; }
public string Name { get; set; }
public List<Employee> Employees { get; set; }
public void RemoveEmployee(int employeeId)
{
Employee empToRemove = null;
foreach (Employee emp in Employees)
{
if (emp.EmployeeId == employeeId)
{
empToRemove = emp;
break;
}
}
if (empToRemove != null)
Employees.Remove(empToRemove);
}
}
public class Employee
{
public int DepartmentId { get; set; }
public int EmployeeId { get; set; }
public string FirsName { get; set; }
public string LastName { get; set; }
}
Workaround: use the ViewInfo.Refresh method instead of the ViewTemplate.Refresh method
To reproduce: use the code from our demo application for Custom Filtering. Instead of Customers table, bind the grid to Orders or another table with 1000+ rows.
Resolution: You can surround the row operation in Begin/EndUpdate(false) and remove the InvalidateRow method. The Custom Filtering example in our demo Application is updated for better performance or you can use the following code snippet:
For example:
private void radGridView1_CustomFiltering(object sender, Telerik.WinControls.UI.GridViewCustomFilteringEventArgs e)
{
if (string.IsNullOrEmpty(this.radTextBox1.Text))
{
this.radGridView1.BeginUpdate();
e.Visible = true;
for (int i = 0; i < this.radGridView1.ColumnCount; i++)
{
e.Row.Cells[i].Style.Reset();
}
//e.Row.InvalidateRow();
this.radGridView1.EndUpdate(false);
return;
}
this.radGridView1.BeginUpdate();
e.Visible = false;
for (int i = 0; i < this.radGridView1.ColumnCount; i++)
{
string text = e.Row.Cells[i].Value.ToString();
if (text.IndexOf(this.radTextBox1.Text, 0, StringComparison.InvariantCultureIgnoreCase) >= 0)
{
e.Visible = true;
e.Row.Cells[i].Style.CustomizeFill = true;
e.Row.Cells[i].Style.DrawFill = true;
e.Row.Cells[i].Style.BackColor = Color.FromArgb(201, 252, 254);
}
else
{
e.Row.Cells[i].Style.Reset();
}
}
//e.Row.InvalidateRow();
this.radGridView1.EndUpdate(false);
}
To reproduce:
Sub New()
InitializeComponent()
Dim dt As New DataTable()
For index = 1 To 13
If index = 4 Then
dt.Columns.Add("Col" & index, Type.GetType("System.Int32"))
Else
dt.Columns.Add("Col" & index)
End If
Next
Dim rand As New Random
For index = 1 To 9000
Dim newRow As DataRow = dt.NewRow()
For Each col As DataColumn In dt.Columns
If col.ColumnName = "Col4" Then
newRow(col.ColumnName) = rand.Next(2, 1000).ToString()
Else
newRow(col.ColumnName) = "Data" & index.ToString() & "." & dt.Columns.IndexOf(col).ToString()
End If
Next
dt.Rows.Add(newRow)
Next
Me.RadGridView1.DataSource = dt
Me.RadGridView1.AutoSizeColumnsMode = Telerik.WinControls.UI.GridViewAutoSizeColumnsMode.Fill
Me.RadGridView1.Columns.RemoveAt(3)
Dim list As New List(Of CustomerMaster)
For index = 1 To 1000
list.Add(New CustomerMaster((index + 1), "Name" & (1000 - index + 1).ToString()))
Next
Dim CustomerMaster_IDColumn As GridViewComboBoxColumn = New GridViewComboBoxColumn
With CustomerMaster_IDColumn
.Name = "CustomerMaster_ID"
.HeaderText = "Customer Master"
.DataSource = list
.ValueMember = "Id"
.DisplayMember = "Name"
.FieldName = "Col4"
.Width = 200
.DisplayMemberSort = True
.DropDownStyle = Telerik.WinControls.RadDropDownStyle.DropDownList
End With
Me.RadGridView1.Columns.Insert(3, CustomerMaster_IDColumn)
End Sub
Public Class CustomerMaster
Private _id As String
Private _name As String
Public Sub New(id As String, name As String)
Me._id = id
Me._name = name
End Sub
Public Property Id() As String
Get
Return _id
End Get
Set(ByVal value As String)
_id = value
End Set
End Property
Public Property Name() As String
Get
Return _name
End Get
Set(ByVal value As String)
_name = value
End Set
End Property
End Class
To reproduce: - Add RadGridView to a blank project and bind it to a blank binding source. - Add GridViewMultiComboBoxColumn to the grid and bind it to another binding source. - In the CellEditorInitialized set the autocomplete mode to Suggest. - When you start the application you will notice that the first items is selected but not displayed and to display it you should select other value first and you will be able to select the first one. Workaround: Set the selected item of the editor to null in the CellEditorInitialized event.
To reproduce:
1.Use the Self-Referencing Hierarchy help article to fill the grid with data.
2.Subscribe to the ChildViewExpanding event and use the following code snippet:
private void radGridView1_ChildViewExpanding(object sender, ChildViewExpandingEventArgs e)
{
if (e.ParentRow.ChildRows != null && e.ParentRow.ChildRows.Count > 0)
{
e.ParentRow.ChildRows[0].Delete();
}
}
To reproduce:
Add a RadGridView and use the RowFormatting event for showing rows with errors. Use a timer to change the data. The RowFormatting event fires when the user does not group rows. But after grouping the rows by any column, the grid is not refreshed according to the applied style in RowFormatting event. In order to reproduce the problem, use the following code:
private readonly BindingList<DataItem> _items = new BindingList<DataItem>();
private readonly Random _rnd = new Random();
public Form1()
{
InitializeComponent();
for (var i = 1; i <= 10; i++)
{
_items.Add(new DataItem("Text1 = " + i, "Type = None", _rnd.Next(0, 2) == 1));
}
radGridView1.DataSource = _items;
timer1.Start();
}
private void radGridView1_RowFormatting(object sender, Telerik.WinControls.UI.RowFormattingEventArgs e)
{
var item = e.RowElement.Data.DataBoundItem as DataItem;
if (item != null && item.IsDataCorrect)
{
e.RowElement.ResetValue(VisualElement.ForeColorProperty, ValueResetFlags.Local);
}
else
{
e.RowElement.ForeColor = Color.Red;
}
}
private void timer1_Tick(object sender, EventArgs e)
{
foreach (var item in _items)
{
item.IsDataCorrect = _rnd.Next(0, 2) == 1;
}
}
ic class DataItem : INotifyPropertyChanged
private bool _isDataCorrect;
private string _text;
private string _type;
public DataItem(string text1, string type, bool isOk)
{
Text = text1;
Type = type;
IsDataCorrect = isOk;
}
public event PropertyChangedEventHandler PropertyChanged;
public bool IsDataCorrect
{
get
{
return _isDataCorrect;
}
set
{
if (_isDataCorrect != value)
{
_isDataCorrect = value;
OnPropertyChanged("IsDataCorrect");
}
}
}
public string Text
{
get
{
return _text;
}
set
{
if (_text != value)
{
_text = value;
OnPropertyChanged("Text1");
}
}
}
public string Type
{
get
{
return _type;
}
set
{
if (_type != value)
{
_type = value;
OnPropertyChanged("Type");
}
}
}
protected virtual void OnPropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
To reproduce:
- Open the hierarchy example in the demo application.
- Select Auto-GenratedDataSet and add a new row in the third level template.
- Select Manually generated for Bound Mode and then re-select Auto-GenratedDataSet
- Try to add new row again. Yo will notice that the new row is not added.
Workaround:
class MyNewRowBehavior : GridNewRowBehavior
{
protected override bool ProcessEnterKey(KeyEventArgs keys)
{
if (this.GridControl.IsInEditMode)
{
GridViewSynchronizationService.SuspendEvent(this.GridControl.CurrentRow.ViewTemplate, KnownEvents.CurrentChanged);
bool result = base.ProcessEnterKey(keys);
GridViewSynchronizationService.ResumeEvent(this.GridControl.CurrentRow.ViewTemplate, KnownEvents.CurrentChanged);
return result;
}
else
{
return base.ProcessEnterKey(keys);
}
}
protected override bool ProcessTabKey(KeyEventArgs keys)
{
if (this.GridControl.IsInEditMode)
{
GridViewSynchronizationService.SuspendEvent(this.GridControl.CurrentRow.ViewTemplate, KnownEvents.CurrentChanged);
bool result = base.ProcessTabKey(keys);
GridViewSynchronizationService.ResumeEvent(this.GridControl.CurrentRow.ViewTemplate, KnownEvents.CurrentChanged);
this.Navigator.SelectNextColumn();
return result;
}
else
{
return base.ProcessTabKey(keys);
}
}
}
The default behavior can be changed as follows:
((BaseGridBehavior)radGridView1.GridBehavior).UnregisterBehavior(typeof(GridViewNewRowInfo));
((BaseGridBehavior)radGridView1.GridBehavior).RegisterBehavior(typeof(GridViewNewRowInfo), new MyNewRowBehavior());
Workaround - listen for Reset of the rows collection and introduce your modification there:
radGridView1.Rows.CollectionChanged += Rows_CollectionChanged;
void Rows_CollectionChanged(object sender, Telerik.WinControls.Data.NotifyCollectionChangedEventArgs e)
{
if (e.Action == Telerik.WinControls.Data.NotifyCollectionChangedAction.Reset)
{
foreach (GridViewRowInfo row in radGridView1.Rows)
{
row.Cells[0].Value = false;
}
}
}
This is not considered an issue, it is how RadGridView works. Here are more details:
In order for a GridDetailViewCellElement to display a pageview instead of a single table element, either the template of the row holding it has to have more than one child template, or its ShowChildViewCaptions should be true.
Once there is a page view, the tabs in it will be visible at all times, except when some of the templates has no rows and AllowAddNewRow for it is false – if it does not have any rows and the user cannot add row, it is considered that there is no need from it.
If one needs to change the visibility of the tabs, this can be done in the ViewCellFormatting event:
private void RadGridView1_ViewCellFormatting(object sender, CellFormattingEventArgs e)
{
GridDetailViewCellElement detailCell = e.CellElement as GridDetailViewCellElement;
if (detailCell != null) {
foreach (RadPageViewItem item in detailCell.PageViewElement.Items) {
item.Visibility = Telerik.WinControls.ElementVisibility.Visible;
}
}
}
To reproduce: - Open the examples solution in Visual Studio. - Navigate to hierarchy example. - Enable the excel like filtering for all templates. - Start the application and open the hierarchy first look example. - Add a new row in the second template. - Add such filter that only the newly added row will remain visible. - Expand the new added row and try to add new row to it.