Workaround: the MasterTemplate has Copy method, which allows overriding in its descendants. Thus, it is possible to modify the copied data according to the specific requirements: public class CustomGrid : RadGridView { protected override RadGridViewElement CreateGridViewElement() { return new CustomRadGridViewElement(); } public override string ThemeClassName { get { return typeof(RadGridView).FullName; } } } public class CustomRadGridViewElement : RadGridViewElement { protected override MasterGridViewTemplate CreateTemplate() { return new CustomMasterGridViewTemplate(); } protected override Type ThemeEffectiveType { get { return typeof(RadGridViewElement); } } } public class CustomMasterGridViewTemplate : MasterGridViewTemplate { public override void Copy() { base.Copy(); if (Clipboard.ContainsData(DataFormats.Text)) { string data = Clipboard.GetData(DataFormats.Text).ToString(); if (data != string.Empty) { StringBuilder sb = new StringBuilder(data); //modify the copied data and replace it in the clipboard Clipboard.SetData(DataFormats.Text, sb.ToString()); } } } }
To reproduce: - Add grid with enabled paging and filtering to a blank form. - Select the second page and apply a filter.
To reproduce: add a RadGridView and bind it to the Northwind.Products data table. Use the following code: private void Form1_Load(object sender, EventArgs e) { this.productsTableAdapter.Fill(this.nwindDataSet.Products); RadMessageBox.Show(string.Format("TOTAL2 = {0}", NewExpression())); } public string NewExpression() { this.radGridView1.Columns.Add(new GridViewDecimalColumn("TOTAL1") { Expression = "ReorderLevel + UnitsOnOrder" }); this.radGridView1.Columns.Add(new GridViewDecimalColumn("TOTAL2") { Expression = "TOTAL1 + UnitPrice" }); //uncomment to get the value of "TOTAL2" // var total1 = this.radGridView1.Rows[2].Cells["TOTAL1"].Value; var total2 = this.radGridView1.Rows[2].Cells["TOTAL2"].Value; return total2.ToString(); } It is not possible to access the column value ("TOTAL2") before firstly to access the column "TOTAL1" value.
To reproduce: - Filer twice by a single column with Excel-like filtering. - The second time InvalidCastException will occur. Workaround: - Create custom columns and override the GetDistinctValues method. public class MyColumn : GridViewTextBoxColumn { protected override GridViewColumnValuesCollection GetDistinctValues() { int index = this.Index; if (index >= 0) { GridViewColumnValuesCollection distinctValues = new GridViewColumnValuesCollection(); foreach (GridViewRowInfo row in this.OwnerTemplate.Rows) { object cellValue = row.Cells[index].Value; if (!distinctValues.Contains(cellValue)) { distinctValues.Add(cellValue); } } if (distinctValues.Count > 0) { return distinctValues; } } return null; } }
To reproduce: - Add grid with a DateTime column with default value "5/1/2014"; - Start the app and press the following keys one after another: 5/1/ - You will notice that the "1" is not replaced. Please note that the similar behavior occur when the year is entered (it does not match the default one). Workaround handle the key press for such cases manually: void radGridView1_CellEditorInitialized(object sender, GridViewCellEventArgs e) { RadDateTimeEditor ed = e.ActiveEditor as RadDateTimeEditor; RadDateTimeEditorElement el = ed.EditorElement as RadDateTimeEditorElement; el.KeyPress += el_KeyPress; } private void el_KeyPress(object sender, KeyPressEventArgs e) { RadDateTimeEditorElement el = (RadDateTimeEditorElement)sender; int day = el.Value.Value.Day; int key = -1; int.TryParse(e.KeyChar.ToString(), key); RadMaskedEditBoxElement element = el.TextBoxElement.TextBoxItem.Parent as RadMaskedEditBoxElement; MaskDateTimeProvider provider = element.Provider as MaskDateTimeProvider; if (provider.SelectedItemIndex == 2) { if (key > 0 & key <= 9) { if (el.TextBoxElement.TextBoxItem.SelectionLength != 0) { if (!booKeying) { dynamic NewValue = new DateTime(el.Value.Value.Year, el.Value.Value.Month, key); el.Value = NewValue; e.Handled = true; booKeying = true; } } } } }
To reproduce: - Add a RadGridView and a button to a blank form. - Subscribe to CellValidating event from the grid and set the cancel property of the CellValidatingEventArgs to true upon some condition. - Add click event handler for the button and print a message in it. - Start the application and enter some invalid data in the grid cell, then click the button. - The code from the button's event handler is executed. Workaround use a flag to determine when to execute the corresponding button code: bool validating = false; void radGridView1_CellValidating(object sender, Telerik.WinControls.UI.CellValidatingEventArgs e) { if (e.Value.ToString().Length < 5) { e.Cancel = true; validating = true; e.Row.ErrorText = "Validation error!"; } else { validating = false; } } private void radButton1_Click(object sender, EventArgs e) { if (!validating) { Debug.WriteLine("Executed"); } }
To reproduce: - Add a grid with some columns to a blank form (the rows should not fill the entire space). - Press and hold the left mouse button, the move the mouse to the empty area of the grid. - Continue to move the mouse and you will notice the event is fired several times. Workaround: - use the CurrentCellChanged event.
Workaround: void radGridView1_PrintCellFormatting(object sender, PrintCellFormattingEventArgs e) { if (e.Column is GridViewImageColumn && e.Row is GridViewDataRowInfo) { e.PrintCell.DrawFill = true; if (radGridView1.PrintStyle.PrintAlternatingRowColor && e.Row.Index % 2 == 1) { e.PrintCell.BackColor = radGridView1.PrintStyle.AlternatingRowColor; } else { e.PrintCell.BackColor = radGridView1.PrintStyle.CellBackColor; } } }
To reproduce: -Add a RadGridView and use the following code snippet: public Form1() { InitializeComponent(); //add GridViewCheckBoxColumn with DataType to BOOL GridViewCheckBoxColumn autoTestingselectColumn = new GridViewCheckBoxColumn(); autoTestingselectColumn.DataType = typeof(bool); autoTestingselectColumn.Name = "AutomatedTestingSelectColumn"; autoTestingselectColumn.FieldName = "AutomatedTestingSelectColumn"; autoTestingselectColumn.HeaderText = "Automated Testing Select"; radGridView1.MasterTemplate.Columns.Add(autoTestingselectColumn); //add GridViewCheckBoxColumn with DataType to INT GridViewCheckBoxColumn startTestingColumn = new GridViewCheckBoxColumn(); startTestingColumn.DataType = typeof(int); startTestingColumn.Name = "StartTestingColumn"; startTestingColumn.FieldName = "StartTestingColumn"; startTestingColumn.HeaderText = "StartTesting"; radGridView1.MasterTemplate.Columns.Add(startTestingColumn); List<Item> items = new List<Item>(); for (int i = 0; i < 5; i++) { items.Add(new Item(Guid.NewGuid().ToString(),"Name"+i)); } this.radGridView1.DataSource = items; //set the AutoSizeColumnsMode property to Fill this.radGridView1.AutoSizeColumnsMode = GridViewAutoSizeColumnsMode.Fill; } public class Item { public string UniqueIdentifier { get; set; } public string Name { get; set; } public Item(string uniqueIdentifier, string name) { this.UniqueIdentifier = uniqueIdentifier; this.Name = name; } } -Run the project. As a result 4 columns are displayed: two programmatically added and two coming from the data source. -Now open the Property Builder at design time and add a GridViewCheckBoxColumn. -Run the project. As a result, 5 columns are displayed: one added at design time, two programmatically added, two coming from the data source. -Open the Property Builder again and delete the GridViewCheckBoxColumn. -Run the project. You will notice that only two columns are displayed. The columns, coming from the data source are not generated. Workaround: delete columns using the Columns collection at design time, instead of using the property Builder.
To reproduce: - Subscribe to the following RowsChanged event handler: void radGridView1_RowsChanged(object sender, GridViewCollectionChangedEventArgs e) { if (e.Action == NotifyCollectionChangedAction.ItemChanged) { GridViewDataRowInfo updrow = (GridViewDataRowInfo)e.NewItems[0]; GridViewDataRowInfo oldrow = (GridViewDataRowInfo)e.OldItems[0]; if (updrow.Cells[2].Value != oldrow.Cells[2].Value) { Console.WriteLine(updrow.Cells[2].Value); Console.WriteLine(oldrow.Cells[2].Value); } } } - You will notice that both values are always equal. Workaround: The CellValidating event can be used instead.
By design the MinHeight property is not respected in ColumnGroupsViewDefinition. The right way to apply MinHeight in the ColumnGroupsViewDefinition is setting the GridViewColumnGroup's RowSpanProperty and GridViewColumnGroupRow's MinHeight property. For example: this.columnGroupsView = new ColumnGroupsViewDefinition(); this.columnGroupsView.ColumnGroups.Add(new GridViewColumnGroup("General") { RowSpan = 40 }); this.columnGroupsView.ColumnGroups.Add(new GridViewColumnGroup("Details") { RowSpan = 40 }); this.columnGroupsView.ColumnGroups[1].Groups.Add(new GridViewColumnGroup("Address") { RowSpan = 40 }); this.columnGroupsView.ColumnGroups[1].Groups.Add(new GridViewColumnGroup("Ime Tam") { RowSpan = 40 }); this.columnGroupsView.ColumnGroups[0].Rows.Add(new GridViewColumnGroupRow() { MinHeight = 40 }); this.columnGroupsView.ColumnGroups[0].Rows.Add(new GridViewColumnGroupRow() { MinHeight = 40 }); this.radGridView1.Columns["ContactName"].RowSpan = 40; this.columnGroupsView.ColumnGroups[0].Rows[0].Columns.Add(this.radGridView1.Columns["CustomerID"]); this.columnGroupsView.ColumnGroups[0].Rows[0].Columns.Add(this.radGridView1.Columns["ContactName"]); this.columnGroupsView.ColumnGroups[0].Rows[1].Columns.Add(this.radGridView1.Columns["CompanyName"]); this.columnGroupsView.ColumnGroups[1].Groups[0].Rows.Add(new GridViewColumnGroupRow() { MinHeight = 40 }); this.columnGroupsView.ColumnGroups[1].Groups[0].Rows[0].Columns.Add(this.radGridView1.Columns["City"]); this.columnGroupsView.ColumnGroups[1].Groups[0].Rows[0].Columns.Add(this.radGridView1.Columns["Country"]); this.columnGroupsView.ColumnGroups[1].Groups[1].Rows.Add(new GridViewColumnGroupRow() { MinHeight = 40 }); this.columnGroupsView.ColumnGroups[1].Groups[1].Rows[0].Columns.Add(this.radGridView1.Columns["Phone"]);
To reproduce: Add a RadGridView and fill it with data. Set the first column's IsVisible property to false. Right click over the row to Copy the row content and paste it in Excel. All data is in a single cell. The Clipboard content does not contain the corresponding <TABLE><TR> tags. Note: if the last columns is hidden, the line-breaks in the copied text are missing. Workaround: create custom RadGridView and replace the wrong content in the Clipboard: public class CustomGrid : RadGridView { protected override RadGridViewElement CreateGridViewElement() { return new CustomRadGridViewElement(); } } public class CustomRadGridViewElement : RadGridViewElement { protected override MasterGridViewTemplate CreateTemplate() { return new CustomMasterGridViewTemplate(); } } public class CustomMasterGridViewTemplate : MasterGridViewTemplate { public override void Copy() { base.Copy(); if (Clipboard.ContainsData(DataFormats.Html)) { string data = Clipboard.GetData(DataFormats.Html).ToString(); StringBuilder sb = new StringBuilder(data); if (!data.Contains("<TABLE>")) { int insertIndex = data.IndexOf("<TD>"); sb.Insert(insertIndex, "<TABLE><TR>"); } else if (!data.Contains("</TABLE>")) { int insertIndex = data.LastIndexOf("<TD>"); sb.Insert(insertIndex, "</TR></TABLE>"); } Clipboard.SetData(DataFormats.Html, sb.ToString()); } } }
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.
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; } } }
Setting the DataSource is slower (about 1/3 times more) when ShowColumnHeaders is set to true. Workaround: Set the ShowColumnHeaders to false, then set the DataSource and restore the ShowColumnHeaders state: radGridView1.ShowColumnHeaders = false; radGridView1.DataSource = mySource; radGridView1.ShowColumnHeaders = true;
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; } } }
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)); } }