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());
To reproduce: public Form1() { InitializeComponent(); for (int i = 0; i < 10; i++) { this.radGridView1.Columns.Add("Col" + i); } for (int i = 0; i < 8000; i++) { GridViewRowInfo row = radGridView1.Rows.NewRow(); foreach (GridViewCellInfo cell in row.Cells) { cell.Value = "Data" + row.Index + "." + cell.ColumnInfo.Index; } radGridView1.Rows.Add(row); } GridViewTemplate childTemplate = CreateChildTemplate(); this.radGridView1.Templates.Add(childTemplate); childTemplate.HierarchyDataProvider = new GridViewEventDataProvider(childTemplate); this.radGridView1.RowSourceNeeded += radGridView1_RowSourceNeeded; } private void radGridView1_RowSourceNeeded(object sender, GridViewRowSourceNeededEventArgs e) { for (int i = 0; i < 10; i++) { GridViewRowInfo row = e.Template.Rows.NewRow(); row.Cells["Name"].Value = "Name" + i; row.Cells["ProductNumber"].Value = "ProductNumber" + i; e.SourceCollection.Add(row); } } private GridViewTemplate CreateChildTemplate() { GridViewTemplate template = new GridViewTemplate(); template.AutoSizeColumnsMode = GridViewAutoSizeColumnsMode.Fill; GridViewTextBoxColumn namecolumn = new GridViewTextBoxColumn("Name"); GridViewTextBoxColumn productNumberColumn = new GridViewTextBoxColumn("ProductNumber"); template.Columns.AddRange(namecolumn, productNumberColumn); return template; } private void radButton1_Click(object sender, EventArgs e) { this.radGridView1.GridNavigator.SelectLastRow(); } Workaround: navigate the vertical scrollbar to the last row before calling the SelectLastRow method: private void radButton1_Click(object sender, EventArgs e) { this.radGridView1.TableElement.RowScroller.Scrollbar.PerformLast(); this.radGridView1.GridNavigator.SelectLastRow(); }
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)); } }
Steps at design time: 1.Add a RadGridView to the from and change its Dock property to Fill. 2.Change its AutoSizeColumnsMode property to Fill. 3.Chage the Form.Size property to Width = 527 and Height = 346. Use the following code: public Form1() { InitializeComponent(); DataTable dt = new DataTable("Items"); dt.Columns.Add("Id", typeof(int)); dt.Columns.Add("Description", typeof(string)); dt.Columns.Add("Price", typeof(decimal)); dt.Columns.Add("Supplier", typeof(string)); for (int i = 0; i < 10; i++) { dt.Rows.Add(i, "Description" + i, i * 0.25, "Supplier" + i); } radGridView1.DataSource = dt; } Workaround: set the AutoSizeColumnsMode property to Fill in the Form.Load event: private void Form1_Load(object sender, EventArgs e) { radGridView1.AutoSizeColumnsMode = GridViewAutoSizeColumnsMode.Fill; }
DECLINED: this happens only when the double click is outside the bounds of the scroll button which is the expected behavior. To reproduce: When the user clicks too fast on the quite thin area between the grid's scroll-bar arrow button and the row, it fires the CurrentRowChanging event. Workaround: private bool cancelChanging = false; private void radGridView1_CurrentRowChanging(object sender, CurrentRowChangingEventArgs e) { if (cancelChanging) { e.Cancel = true; cancelChanging = false; } } private void radGridView1_MouseDoubleClick(object sender, MouseEventArgs e) { cancelChanging = false; RadElement element = this.radGridView1.Behavior.GetHoveredRadElement(); while (element != null) { if (element.GetType() == typeof(RadScrollBarElement)) { cancelChanging = true; break; } element = element.Parent; } }
To reproduce: Add a RadGridView and use the following code. When you expand the first row, the vertical scrollbar is not correct. Scrolling down changes its size. However, if you expand the last row, it takes few seconds to open. Second scenario: In addition of the following code, if you change the TableElement.PageViewMode to PageViewMode.ExplorerBar, expanding the first row takes few seconds to load the hierarchical data as well. public partial class Form1 : Form { public Form1() { InitializeComponent(); List<Item> items = new List<Item>(); List<SubItem> subItems = new List<SubItem>(); for (int i = 1; i <= 3; i++) { Item item = new Item(i, "Item" + i); for (int j = 1000; j <= 2010; j++) { subItems.Add(new SubItem(j, "SubItem" + j, i)); } items.Add(item); } this.radGridView1.DataSource = items; this.radGridView1.AutoSizeColumnsMode = GridViewAutoSizeColumnsMode.Fill; GridViewTemplate template = new GridViewTemplate(); template.ReadOnly = true; template.AutoSizeColumnsMode = GridViewAutoSizeColumnsMode.Fill; GridViewRelation relation = new GridViewRelation(this.radGridView1.MasterTemplate, template); relation.ParentColumnNames.Add("Id"); relation.ChildColumnNames.Add("ItemId"); this.radGridView1.MasterTemplate.Templates.Add(template); this.radGridView1.Relations.Add(relation); template.DataSource = subItems; } } public class Item { public int Id { get; set; } public string Title { get; set; } public Item(int id, string title) { this.Id = id; this.Title = title; } } public class SubItem { public int Id { get; set; } public int ItemId { get; set; } public string Name { get; set; } public SubItem(int id, string name, int itemId) { this.Id = id; this.ItemId = itemId; this.Name = name; } }
To reproduce: 1.Add a GridViewCheckBoxColumn and populate the grid with data: radGridView1.DataSource = Enumerable.Range(1, 100).Select(i => new { Check = i % 2 == 0}); 2.Add a RadButton and on its Click event clear the filters: private void radButton1_Click(object sender, EventArgs e) { radGridView1.MasterTemplate.FilterDescriptors.Clear(); } 3.Run the application and change the filter to show only checked items. Then click the button. The check box in the filtering row for GridViewCheckBoxColumn was not updated properly. Workaround: this.radGridView1.BeginUpdate(); radGridView1.MasterTemplate.FilterDescriptors.Clear(); this.radGridView1.EndUpdate();
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(); } }
This issue appears when one clears the relations collection of RadGridView, it appears sporadically and in rare cases
To reproduce: Create a form and add a timer with interval of 1 second and in tick handler do the following: void t_Tick(object sender, EventArgs e) { if (this.Controls.Count > 0) { Control oldGrid = this.Controls[0]; this.Controls.RemoveAt(0); oldGrid.Dispose(); GC.Collect(3, GCCollectionMode.Forced); } RadGridView grid = new RadGridView(); grid.Dock = DockStyle.Fill; this.Controls.Add(grid); } You will see that the memory consumption will grow. Workaround: Use the following custom RadGridView public class MyRadGridView : RadGridView { protected override RadGridViewElement CreateGridViewElement() { return new MyElement(); } } public class MyElement : RadGridViewElement { protected override PagingPanelElement CreatePagingPanelElement() { return new MyPagingPanel(); } protected override Type ThemeEffectiveType { get { return typeof(RadGridViewElement); } } } public class MyPagingPanel : PagingPanelElement { protected override void CreateButtonsStripElementChildElements() { base.CreateButtonsStripElementChildElements(); this.ButtonsStripElement.Children.Add(this.ButtonsStripElement.Grip); this.ButtonsStripElement.Children.Add(this.ButtonsStripElement.OverflowButton); this.ButtonsStripElement.Grip.Visibility = this.ButtonsStripElement.OverflowButton.Visibility = ElementVisibility.Collapsed; } protected override void CreateTextBoxStripElementChildElements() { base.CreateTextBoxStripElementChildElements(); this.TextBoxStripElement.Children.Add(this.TextBoxStripElement.Grip); this.TextBoxStripElement.Children.Add(this.TextBoxStripElement.OverflowButton); this.TextBoxStripElement.Grip.Visibility = this.TextBoxStripElement.OverflowButton.Visibility = ElementVisibility.Collapsed; } }
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.
Add the ability to filter by empty values (not null values) just like in excel.
To reproduce: - Add some rows to a grid view and set the ClipboardCopyMode to EnableAlwaysIncludeHeaderText. - Copy entire row and paste it in excel. You will notice that the columns are pasted right, but the cells values are merged. - Also when multiple rows are copied the issue does not occur.
The RadGridView designer allows you to add columns and make changes while debugging the application. When you click the Ok button it tells you that your changes cannot be applied and everything is lost. I've done this several times by accident and didn't realize I was debugging until my changes were lost. Maybe disallow making changes to the columns while debugging?
The binding source filtering should be synchronized with the grid one in case other controls are using the same binding source.
To reproduce: - Set the AutoSizeRows and PrintGrouping properties to true. - Add a group descriptor and then call the PrintPreview method of the grid. Workaround: - Use the following classes to create custom print style: public class MyGridPrintRenderer : TableViewDefinitionPrintRenderer { private RadGridView gridView; public MyGridPrintRenderer(RadGridView grid) : base(grid) { gridView = grid; } protected override int GetDataRowHeight(GridViewRowInfo row, TableViewRowLayoutBase rowLayout) { IVirtualizedElementProvider<GridViewRowInfo> rowElementProvider = this.gridView.TableElement.RowScroller.ElementProvider; GridRowElement visualRow = rowElementProvider.GetElement(row, null) as GridRowElement; if (visualRow is GridGroupHeaderRowElement) { return rowLayout.GetRowHeight(row); } return base.GetDataRowHeight(row, rowLayout); } } public class MyGridPrintSyle : GridPrintStyle { protected override BaseGridPrintRenderer InitializePrintRenderer(RadGridView grid) { if (this.PrintRenderer != null) { this.PrintRenderer.PrintCellPaint -= renderer_PrintCellPaint; this.PrintRenderer.PrintCellFormatting -= renderer_PrintCellFormatting; } MyGridPrintRenderer renderer = new MyGridPrintRenderer(grid); renderer.PrintCellFormatting += renderer_PrintCellFormatting; renderer.PrintCellPaint += renderer_PrintCellPaint; return renderer; } private void renderer_PrintCellPaint(object sender, PrintCellPaintEventArgs e) { this.OnPrintCellPaint(sender, e); } private void renderer_PrintCellFormatting(object sender, PrintCellFormattingEventArgs e) { this.OnPrintCellFormatting(sender, e); } }
To reproduce: Add a RadGridView and three GridViewComboBoxColumns with repetitive values: for (int i = 0; i < 3; i++) { List<int> datasource = new List<int>(); for (int j = 0; j < 12; j++) { datasource.Add(j); } this.Grid.Columns.Add(new GridViewComboBoxColumn() { DataSource = datasource }); } for (int i = 0; i < 10; i++) { for (int j = 0; j < 5; j++) { this.Grid.Rows.Add(i, i, i); } } Start the project and sort second and last column by the same value and make sure that you have vertical scrollbar. Select a cell in the second column change its value and press the tab key(or click on another cell in the same row). You will see that the scrollbar will go to the bottom of the grid. Workaround: Use the following class: public class ActionExecuteHelper { #region Singleton private static ActionExecuteHelper instance; private static readonly object syncRoot = new object(); public static ActionExecuteHelper Instance { get { if (instance == null) { lock (syncRoot) { if (instance == null) { instance = new ActionExecuteHelper(); } } } return instance; } } #endregion private readonly Timer timer; public ActionExecuteHelper() { this.timer = new Timer(); } public void ExecuteDelayedAction(Action action, int delayInMilliseconds) { EventHandler timerTick = null; timerTick = delegate { this.timer.Stop(); this.timer.Tick -= timerTick; action.Invoke(); }; this.timer.Tick += timerTick; this.timer.Interval = delayInMilliseconds; this.timer.Start(); } } And use it with the following code private int savedValue; private void Grid_CellEndEdit(object sender, GridViewCellEventArgs e) { this.Grid.TableElement.VScrollBar.ValueChanged += ValueChangedDelegate; } private void ValueChangedDelegate(object sender, EventArgs e) { this.Grid.TableElement.VScrollBar.ValueChanged -= ValueChangedDelegate; ActionExecuteHelper.Instance.ExecuteDelayedAction(new Action(this.SetScrollbarValue), 5); } private void SetScrollbarValue() { this.Grid.TableElement.VScrollBar.Value = savedValue; } private void Grid_ValueChanging(object sender, ValueChangingEventArgs e) { this.savedValue = this.Grid.TableElement.VScrollBar.Value; } This way the value of the scrollbar will be saved and restored.
Description: When you pin data rows from the child template to PinnedRowPosition.Top, it does not affect the row. However, when you pin the certain row to PinnedRowPosition.Bottom, the behavior is correct. The same issue is detected for the header rows from the child template.
Workaround: use the CellValidating event