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); } }
To reproduce: use the following code snippet and follow the steps illustrated on the attached gif file: private void Form1_Load(object sender, EventArgs e) { this.customersTableAdapter.Fill(this.nwindDataSet.Customers); this.radGridView1.DataSource = this.customersBindingSource; this.radGridView1.BestFitColumns(BestFitColumnMode.AllCells); ColumnGroupsViewDefinition view = new ColumnGroupsViewDefinition(); view.ColumnGroups.Add(new GridViewColumnGroup("Customer Contact")); view.ColumnGroups.Add(new GridViewColumnGroup("Details")); view.ColumnGroups[1].Groups.Add(new GridViewColumnGroup("Address")); view.ColumnGroups[1].Groups.Add(new GridViewColumnGroup("Contact")); view.ColumnGroups[0].Rows.Add(new GridViewColumnGroupRow()); view.ColumnGroups[0].Rows[0].Columns.Add(this.radGridView1.Columns["CompanyName"]); view.ColumnGroups[0].Rows[0].Columns.Add(this.radGridView1.Columns["ContactName"]); view.ColumnGroups[0].Rows[0].Columns.Add(this.radGridView1.Columns["ContactTitle"]); view.ColumnGroups[1].Groups[0].Rows.Add(new GridViewColumnGroupRow()); view.ColumnGroups[1].Groups[0].Rows[0].Columns.Add(this.radGridView1.Columns["Address"]); view.ColumnGroups[1].Groups[0].Rows[0].Columns.Add(this.radGridView1.Columns["City"]); view.ColumnGroups[1].Groups[0].Rows[0].Columns.Add(this.radGridView1.Columns["Country"]); view.ColumnGroups[1].Groups[1].Rows.Add(new GridViewColumnGroupRow()); view.ColumnGroups[1].Groups[1].Rows[0].Columns.Add(this.radGridView1.Columns["Phone"]); view.ColumnGroups[1].Groups[1].Rows[0].Columns.Add(this.radGridView1.Columns["Fax"]); radGridView1.ViewDefinition = view; } Sometimes the incorrect behavior is obtained immediately after you drop the column, but you need to scroll the horizontal scroll-bar to replicate it. Workaround: RadGridViewDragDropService svc = this.radGridView1.GridViewElement.GetService<RadGridViewDragDropService>(); svc.Stopped += svc_Stopped; private void svc_Stopped(object sender, EventArgs e) { int horizontalScrollvalue = this.radGridView1.TableElement.HScrollBar.Value; this.radGridView1.MasterTemplate.Refresh(); this.radGridView1.TableElement.HScrollBar.Value = horizontalScrollvalue; }
To reproduce: following the illustrated steps: http://screencast.com/t/D2TCpU2zo Workaround: set up the hierarchy programmatically.
When a Right-To-Left grid is printed the text of all print cells should be drawn with the StringFormatFlags.DirectionRightToLeft. Example: RadGridView with RightToLeft set to Yes A decimal column with negative values the values in the decimal column are drawn as 96-, 88- etc if this grid is printed the values will be -96, -88 Workaround: http://www.telerik.com/community/forums/radprintdocument-from-a-grid-wrong-format-when-right-to-left-true-in-grid
Allow setting the height of the group panel in design time: - by setting its height property - by using mouse cursor via property builder
RadGridView - You cannot select cells only from Pinned Columns if under them there is unpinned one. Steps to reproduce: 1. Set SelectionMode property of RadGridView to GridViewSelectionMode.CellSelect. 2. Create 3 left pinned columns 3. Create several unpinned columns. 4. Scroll horizontal scroll bar to hide several unpinned columns under the pinned. 5. Try to select only pinned cells with the selection rectangle.
Add the ability to filter by empty values (not null values) just like in excel.
A user should be able to disable executing any of the cut/copy/paste (ctrl+x, ctrl+c, ctrl+v) commands.
RadGridView If FilteringMode is set to DisplayMember if one clicks in the ComboBoxColumn cell; the actual cell value goes blank. If FilteringMode is set to ValueMember the ComboBoxColumn behaves as expected. Workaround: Private Sub RadGridView1_CellEditorInitialized(sender As Object, e As GridViewCellEventArgs) Handles RadGridView1.CellEditorInitialized If e.ActiveEditor.GetType() Is GetType(RadDropDownListEditor) Then e.ActiveEditor.Value = e.Value End If End Sub
Workaround: use the following custom editor: using System; using Telerik.WinControls.UI; namespace radGridView_MultipleFilters { public class CustomRadMultiColumnComboBoxElement : RadMultiColumnComboBoxElement { protected override Type ThemeEffectiveType { get { return typeof(RadMultiColumnComboBoxElement); } } public GridViewDataColumn DisplayColumn { get { string displayMember = this.DisplayMember; if (string.IsNullOrEmpty(displayMember)) { for (int i = 0; i < this.MultiColumnPopupForm.EditorControl.Columns.Count; i++) { if (this.MultiColumnPopupForm.EditorControl.Columns[i].DataType == typeof(string)) { displayMember = this.MultiColumnPopupForm.EditorControl.Columns[i].FieldName; break; } } if (this.MultiColumnPopupForm.EditorControl.Columns.Count > 0 && string.IsNullOrEmpty(displayMember)) { displayMember = this.MultiColumnPopupForm.EditorControl.Columns[0].FieldName; } } DisplayMember = displayMember; GridViewDataColumn[] columns = this.MultiColumnPopupForm.EditorControl.Columns.GetColumnByFieldName(displayMember); if (columns.Length > 0) { return columns[0]; } return null; } } protected override object FindItemExact(string text) { int index = this.FindItemIndexExact(text); if (index != -1) { return this.EditorControl.ChildRows[index]; } return null; } protected override void SetActiveItem(string text) { int rowIndex = this.FindItemIndexExact(text); if (rowIndex != -1) { this.EditorControl.CurrentRow = this.EditorControl.ChildRows[rowIndex]; this.Select(this.Text.Length, 0); } } protected override int FindItemIndexExact(string text) { GridViewRowInfo rowInfo = this.FindItemExact(text, this.DisplayColumn.Name); if (rowInfo != null) { return rowInfo.Index; } return -1; } protected override GridViewRowInfo FindItemExact(string text, string field) { GridViewDataColumn[] foundColumns = this.EditorControl.Columns.GetColumnByFieldName(field); if (foundColumns.Length > 0) { for (int i = 0; i < this.EditorControl.ChildRows.Count; i++) { object element = this.EditorControl.ChildRows[i].Cells[foundColumns[0].Name].Value; string elementText = Convert.ToString(element); if (!string.IsNullOrEmpty(elementText) && elementText.Equals(text, this.EditorControl.MasterTemplate.CaseSensitive ? StringComparison.InvariantCulture : StringComparison.InvariantCultureIgnoreCase)) { return this.EditorControl.ChildRows[i]; } } } return null; } } }
One should be able to replace the exported file if such exists.
Filtering is applied, if you clear the filter descriptors and enable/disable custom filtering. Steps to reproduce: 1. Click on the filter button on the Name header. Check only one name, and only one record should be visible in the grid. 2. Click the Clear button. All records should now be visible. 3. Click the Toggle Filter button once, to enable custom filtering. 4. Click the Toggle Filter button again to disable custom filtering. Workaround: private static readonly FieldInfo FilterContextFieldInfo = typeof(RadCollectionView<GridViewRowInfo>).GetField("filterContext", BindingFlags.NonPublic | BindingFlags.Instance); this.radGridView1.FilterDescriptors.Clear(); StringCollection filterContext = FilterContextFieldInfo.GetValue(this.radGridView1.MasterTemplate.DataView) as StringCollection; filterContext.Clear();
To reproduce: -add a RadGridView and bind it to Northwind.Customers datatable. -try to edit a random row and change its CustomerID cell to an already existing one. Workaround: use custom GridViewDataRowInfo: public class CustomRowInfo : GridViewDataRowInfo { public CustomRowInfo(GridViewInfo viewInfo) : base(viewInfo) { } protected override bool OnEndEdit() { IEditableObject dataItem = this.DataBoundItem as IEditableObject; if (dataItem != null) { try { dataItem.EndEdit(); } catch (Exception ex) { this.ViewTemplate.SetError(new GridViewCellCancelEventArgs(null,null, null), ex); } } return base.OnEndEdit(); } }
To reproduce: 1. Set the RadGridView.MultiSelect property to true. 2. Set the SelectionMode = Telerik.WinControls.UI.GridViewSelectionMode.CellSelect 3. When you select multiple cells, the SelectedCells collection stores the cells in reversed order instead of keeping the selection order. Compared to GridViewSelectionMode.FullRowSelect, this behavior is different. Workaround: iterate the SelectedCells collection in reversed order
To reproduce: use the following code snippet and refer to the attached gif file: public Form1() { InitializeComponent(); for (int i = 0; i < 20; i++) { this.radGridView1.Columns.Add("Col" + i); } for (int i = 0; i < 10; i++) { GridViewDataRowInfo row = this.radGridView1.Rows.AddNew() as GridViewDataRowInfo; foreach (GridViewColumn col in this.radGridView1.Columns) { row.Cells[col.Name].Value = "Data" + row.Index + "." + col.Index; } } this.radGridView1.MultiSelect = true; this.radGridView1.SelectionMode = GridViewSelectionMode.CellSelect; } Workaround: int startColumn = int.MaxValue; int endColumn = 0; int startRow = int.MaxValue; int endRow = 0; private void radGridView1_MouseDown(object sender, MouseEventArgs e) { GridDataCellElement cellElement = this.radGridView1.ElementTree.GetElementAtPoint(e.Location) as GridDataCellElement; if (cellElement != null) { startColumn = cellElement.ColumnIndex; startRow = cellElement.RowIndex; } } private void radGridView1_MouseUp(object sender, MouseEventArgs e) { GridDataCellElement cellElement = this.radGridView1.ElementTree.GetElementAtPoint(e.Location) as GridDataCellElement; if (cellElement != null) { endColumn = cellElement.ColumnIndex; endRow = cellElement.RowIndex; } if (endColumn < startColumn) { int swap = endColumn; endColumn = startColumn; startColumn = swap; } if (endRow < startRow) { int swap = endRow; endRow = startRow; startRow = swap; } this.radGridView1.ClearSelection(); int scrollBarValue = this.radGridView1.TableElement.HScrollBar.Value; this.radGridView1.BeginUpdate(); for (int i = startRow; i < endRow + 1; i++) { for (int j = startColumn; j < endColumn + 1; j++) { if (!this.radGridView1.Rows[i].Cells[j].IsSelected) { this.radGridView1.Rows[i].Cells[j].IsSelected = true; } } } this.radGridView1.EndUpdate(); this.radGridView1.TableElement.HScrollBar.Value = scrollBarValue; }
RadGridView - current row changes even when canceling the RowValidating event. Code to reproduce: public Form1() { InitializeComponent(); radGridView1.AutoGenerateColumns = false; radGridView1.AutoSizeColumnsMode = GridViewAutoSizeColumnsMode.Fill; radGridView1.Columns.Add(new GridViewTextBoxColumn("A", "A")); radGridView1.Columns.Add(new GridViewTextBoxColumn("B", "B")); radGridView1.Columns.Add(new GridViewTextBoxColumn("C", "C")); radGridView1.Rows.Add("A", "AA", "AAA"); radGridView1.Rows.Add("B", "BB", "BBB"); radGridView1.Rows.Add("C", "CC", "CCC"); radGridView1.Rows.Add("D", "DD", "DDD"); radGridView1.Rows.Add("E", "EE", "EEE"); radGridView1.Rows.Add("F", "FF", "FFF"); radGridView1.Rows.Add("G", "GG", "GGG"); radGridView1.RowValidating += new RowValidatingEventHandler(radGridView1_RowValidating); } void radGridView1_RowValidating(object sender, RowValidatingEventArgs e) { if (e.Row.Cells["B"].Value.ToString() == "BB") { e.Cancel = true; } } Steps to reproduce: 1. Go to cell with value "BB" 2. NOT in edit mode press down arrow key 2-3 times 3. Change text to "AA" 4. Press Tab several times Work around: Use custom navigator: radGridView1.GridViewElement.Navigator = new MyGridNavigator(); public class MyGridNavigator : BaseGridNavigator { private static readonly FieldInfo EnumeratorFieldInfo = typeof(BaseGridNavigator).GetField("enumerator", BindingFlags.NonPublic | BindingFlags.Instance); protected GridTraverser enumerator { get { return EnumeratorFieldInfo.GetValue(this) as GridTraverser; } } protected override bool SelectCore(GridViewRowInfo row, GridViewColumn column) { bool result = base.SelectCore(row, column); if (!result) { enumerator.GoToRow(this.GridViewElement.CurrentRow); } return result; } }
1. Create a new project with RadGridView and set MultiSelect to true and SelectionMode to CellSelect. 2. Run the project. 3. Use the mouse to select some cells and scroll down while selecting. 4. Remove some cells from the selection. 5. Scroll with the scrollbar up to the first selected cells. You will see that all previously selected cells which are not visible are not selected. Workaround: Use the following custom behavior: public class MyGridRowBehavior : GridDataRowBehavior { private FieldInfo oldCurrentLocationFieldInfo; private Point oldCurrentLocation { get { if (this.oldCurrentLocationFieldInfo == null) { this.oldCurrentLocationFieldInfo = typeof(GridRowBehavior).GetField("oldCurrentLocation", BindingFlags.Instance | BindingFlags.NonPublic); } return (Point)this.oldCurrentLocationFieldInfo.GetValue(this); } set { this.oldCurrentLocationFieldInfo.SetValue(this, value); } } private MethodInfo selectIntersectedCellsMethodInfo; private delegate void SelectIntersectedCellsDelegate(RadElementCollection rows, bool isProcessedShiftOrControl); private SelectIntersectedCellsDelegate SelectIntersectedCellsCore; private void SelectIntersectedCells(RadElementCollection rows, bool isProcessedShiftOrControl) { if (this.selectIntersectedCellsMethodInfo == null) { this.selectIntersectedCellsMethodInfo = typeof(GridRowBehavior).GetMethods(BindingFlags.Instance | BindingFlags.NonPublic).First(x => x.Name == "SelectIntersectedCells" && x.GetParameters().Length == 2); this.SelectIntersectedCellsCore = (SelectIntersectedCellsDelegate)Delegate.CreateDelegate(typeof(SelectIntersectedCellsDelegate), this, this.selectIntersectedCellsMethodInfo); } this.SelectIntersectedCellsCore(rows, isProcessedShiftOrControl); } private MethodInfo selectIntersectedRowsMethodInfo; private delegate bool SelectIntersectedRowsDelegate(RadElementCollection rows); private SelectIntersectedRowsDelegate SelectIntersectedRowsCore; private bool SelectIntersectedRows(RadElementCollection rows) { if (this.selectIntersectedRowsMethodInfo == null) { this.selectIntersectedRowsMethodInfo = typeof(GridRowBehavior).GetMethod("SelectIntersectedRows", BindingFlags.Instance | BindingFlags.NonPublic); this.SelectIntersectedRowsCore = (SelectIntersectedRowsDelegate)Delegate.CreateDelegate(typeof(SelectIntersectedRowsDelegate), this, this.selectIntersectedRowsMethodInfo); } return this.SelectIntersectedRowsCore(rows); } protected override bool ProcessMouseSelection(Point mousePosition, GridCellElement currentCell) { if (this.RootGridBehavior.LockedBehavior != this) { this.GridControl.Capture = true; this.RootGridBehavior.LockBehavior(this); } GridCellElement mouseDownCell = this.GetCellAtPoint(this.MouseDownLocation); GridCellElement oldCurrentCell = this.GetCellAtPoint(this.oldCurrentLocation); bool isValidResizingContext = this.ResizeSelectionRectangle(currentCell, mousePosition); bool result = false; if (isValidResizingContext && oldCurrentCell != currentCell) { if (this.MasterTemplate.MultiSelect && !this.GridViewElement.Template.AllowRowReorder) { if (this.MasterTemplate.SelectionMode == GridViewSelectionMode.FullRowSelect) { bool selectedRowsChanged = false; bool isPressedShiftOrControl = (this.IsPressedShift || this.IsPressedControl); GridTableElement tableElement = this.GridViewElement.CurrentView as GridTableElement; RadElementCollection scrollableRows = tableElement.ViewElement.ScrollableRows.Children; RadElementCollection topPinnedRows = tableElement.ViewElement.TopPinnedRows.Children; RadElementCollection bottomPinnedRows = tableElement.ViewElement.BottomPinnedRows.Children; GridViewRowInfo[] selectedRows = this.MasterTemplate.SelectedRows.ToArray(); tableElement.BeginUpdate(); int oldSelectedRows = this.MasterTemplate.SelectedRows.Count; if (!isPressedShiftOrControl) { for (int i = selectedRows.Length - 1; i >= 0; i--) { GridViewRowInfo rowInfo = selectedRows[i]; GridRowElement rowElement = tableElement.GetRowElement(rowInfo); bool select = rowElement != null && rowElement.ControlBoundingRectangle.IntersectsWith(this.GridViewElement.SelectionRectangle); if (select) { rowInfo.IsSelected = true; } if (!rowInfo.IsSelected) { selectedRowsChanged = true; } } } selectedRowsChanged = this.SelectIntersectedRows(topPinnedRows); selectedRowsChanged |= this.SelectIntersectedRows(scrollableRows); selectedRowsChanged |= this.SelectIntersectedRows(bottomPinnedRows); if (oldSelectedRows != this.MasterTemplate.SelectedRows.Count) { selectedRowsChanged = true; } tableElement.EndUpdate(false); } else { GridTableElement tableElement = this.GridViewElement.CurrentView as GridTableElement; if (tableElement == null) { return result; } CancelEventArgs cancelArgs = new CancelEventArgs(); this.MasterTemplate.EventDispatcher.RaiseEvent<CancelEventArgs>(EventDispatcher.SelectionChanging, this, cancelArgs); if (cancelArgs.Cancel) { return result; } //Since version Q2 2014 (version 2014.2.617), please use: //GridViewSelectionCancelEventArgs cancelArgs = new GridViewSelectionCancelEventArgs(this.MasterTemplate.CurrentRow, this.MasterTemplate.CurrentColumn); //this.MasterTemplate.EventDispatcher.RaiseEvent<GridViewSelectionCancelEventArgs>(EventDispatcher.SelectionChanging, this, cancelArgs); //if (cancelArgs.Cancel) //{ // return result; //} this.GridViewElement.CurrentView.BeginUpdate(); bool isProcessedShiftOrControl = (this.IsPressedShift || this.IsPressedControl); int count = this.MasterTemplate.SelectedCells.Count; RadElementCollection scrollableRows = tableElement.ViewElement.ScrollableRows.Children; RadElementCollection topPinnedRows = tableElement.ViewElement.TopPinnedRows.Children; RadElementCollection bottomPinnedRows = tableElement.ViewElement.BottomPinnedRows.Children; this.SelectIntersectedCells(scrollableRows, isProcessedShiftOrControl); this.SelectIntersectedCells(topPinnedRows, isProcessedShiftOrControl); this.SelectIntersectedCells(bottomPinnedRows, isProcessedShiftOrControl); bool notifyUpdates = true; if (isProcessedShiftOrControl) { notifyUpdates = count != this.MasterTemplate.SelectedCells.Count; } this.GridViewElement.CurrentView.EndUpdate(false); this.GridViewElement.Invalidate(); } result = true; } result = false; } this.oldCurrentLocation = mousePosition; return result; } } Register the new behavior as follows: BaseGridBehavior behavior = (BaseGridBehavior)this.radGridView1.GridBehavior; behavior.UnregisterBehavior(typeof(GridViewDataRowInfo)); behavior.RegisterBehavior(typeof(GridViewDataRowInfo), new MyGridRowBehavior());
Allow RadGridVIew Exports to perform independently in BackgroundWorker without suspending UI thread of RadGridView.
It takes more than a minute to export 15000 cells. To reproduce: public Form1() { InitializeComponent(); //populate with data DataTable dt = new DataTable(); for (int i = 0; i < 50; i++) { dt.Columns.Add("Col" + i, typeof(string)); } DataColumn col; for (int i = 0; i < 3000; i++) { DataRow newRow = dt.Rows.Add(); for (int j = 0; j < dt.Columns.Count; j++) { col = dt.Columns[j]; newRow[col.ColumnName] = "Data." + i + " " + dt.Columns.IndexOf(col); } } this.radGridView1.DataSource = dt; this.radGridView1.BestFitColumns(Telerik.WinControls.UI.BestFitColumnMode.AllCells); } private void radButton1_Click(object sender, EventArgs e) { Telerik.WinControls.UI.Export.SpreadExport.SpreadExport spreadExporter; spreadExporter = new SpreadExport(this.radGridView1,SpreadExportFormat.Xlsx ); spreadExporter.ExportVisualSettings = false; SaveFileDialog dialog = new SaveFileDialog(); dialog.FilterIndex = 1; dialog.DefaultExt = "*.xlsx"; dialog.Filter = "Excel file |*.xlsx"; if (dialog.ShowDialog() == DialogResult.OK) { Stopwatch sw = new Stopwatch(); sw.Start(); string fileName = dialog.FileName; spreadExporter.RunExport(fileName); sw.Stop(); Console.WriteLine(string.Format("Elapsed {0}", sw.Elapsed)); Process.Start(fileName); } }
To reproduce: Open Demo application >> GridView >> Export >> Export Hierarchy