To reproduce: 1. Run the attached application. 2. Click into the cell in Column One and expand the combo box 3. While the combo box is still expanded, right click on any header cell in the grid Step 3 should result in a NullReferenceException Workaround: Friend Class MyGridHeaderCellElement Inherits GridHeaderCellElement Public Sub New(ByVal col As GridViewColumn, ByVal row As GridRowElement) MyBase.New(col, row) End Sub Protected Overrides Sub ShowContextMenu() If Me.ViewTemplate IsNot Nothing Then MyBase.ShowContextMenu() End If End Sub Protected Overrides ReadOnly Property ThemeEffectiveType() As Type Get Return GetType(GridHeaderCellElement) End Get End Property End Class Private Sub radGridView1_CreateCell(ByVal sender As Object, ByVal e As GridViewCreateCellEventArgs) If Object.ReferenceEquals(e.CellType, GetType(GridHeaderCellElement)) Then e.CellType = GetType(MyGridHeaderCellElement) End If End Sub
To reproduce: public Form1() { InitializeComponent(); DataTable dt = new DataTable(); for (int i = 0; i < 5; i++) { dt.Columns.Add("Col"+i); } for (int i = 0; i < 2000; i++) { DataRow row = dt.NewRow(); foreach (DataColumn col in dt.Columns) { row[col.ColumnName] = "Data" + i + "." + dt.Columns.IndexOf(col); } dt.Rows.Add(row); } this.radGridView1.DataSource = dt; this.radGridView1.AutoSizeColumnsMode = Telerik.WinControls.UI.GridViewAutoSizeColumnsMode.Fill; } private void radButton1_Click(object sender, EventArgs e) { RadPrintPreviewDialog dialog = new RadPrintPreviewDialog(); dialog.Document = this.radPrintDocument1; dialog.ShowDialog(); } Workaround: this.radGridView1.AutoSizeRows = true;
To reproduce: Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load Me.RadGridView1.AutoGenerateColumns = False Dim column = New GridViewTextBoxColumn column.Name = "Name" column.FieldName = "ChildItem" column.DataType = GetType(CustomItem) column.DataTypeConverter = New CustomItemTypeConverter() Me.RadGridView1.Columns.Add(column) Me.RadGridView1.AutoSizeColumnsMode = GridViewAutoSizeColumnsMode.Fill Dim objects = { New CustomContainer With {.ChildItem = New CustomItem With {.Name = "A"}}, New CustomContainer With {.ChildItem = New CustomItem With {.Name = "B"}}, New CustomContainer With {.ChildItem = New CustomItem With {.Name = "C"}} } Me.RadGridView1.DataSource = objects End Sub Private Sub RadGridView_EditorRequired(sender As Object, e As EditorRequiredEventArgs) Handles RadGridView1.EditorRequired e.EditorType = GetType(GridSpinEditor) End Sub Class CustomContainer Public Property ChildItem As CustomItem End Class Class CustomItem Public Property Name As String End Class Class CustomItemTypeConverter Inherits TypeConverter Public Overrides Function CanConvertFrom(context As ITypeDescriptorContext, sourceType As Type) As Boolean If sourceType = GetType(Decimal) Then Return True End If Return MyBase.CanConvertFrom(context, sourceType) End Function Public Overrides Function CanConvertTo(context As ITypeDescriptorContext, destinationType As Type) As Boolean If destinationType = GetType(Decimal) OrElse destinationType = GetType(String) OrElse destinationType = GetType(CustomItem) Then Return True End If Return MyBase.CanConvertTo(context, destinationType) End Function Public Overrides Function ConvertTo(context As ITypeDescriptorContext, culture As System.Globalization.CultureInfo, _ value As Object, destinationType As Type) As Object If TypeOf value Is CustomItem Then Dim customValue = DirectCast(value, CustomItem) If destinationType = GetType(Decimal) Then Return Microsoft.VisualBasic.AscW(customValue.Name.Chars(0)) ElseIf destinationType = GetType(String) Then Return customValue.Name ElseIf destinationType = GetType(CustomItem) Then Return customValue Else Return MyBase.ConvertTo(context, culture, value, destinationType) End If End If Return MyBase.ConvertTo(context, culture, value, destinationType) End Function Public Overrides Function ConvertFrom(context As ITypeDescriptorContext, culture As System.Globalization.CultureInfo, value As Object) As Object If TypeOf value Is Decimal Then Dim decValue = DirectCast(value, Decimal) Dim intValue = CInt(decValue) Dim charValue = Microsoft.VisualBasic.ChrW(intValue) Return New CustomItem With {.Name = New String(charValue, 1)} End If Return MyBase.ConvertFrom(context, culture, value) End Function End Class Workaround: Public Class MyEditor Inherits GridSpinEditor Public Overrides ReadOnly Property IsModified() As Boolean Get If Me.originalValue Is Nothing Then Return (Me.Value IsNot Nothing AndAlso Me.Value <> DBNull.Value) End If If Me.Value Is Nothing Then Return (Me.originalValue IsNot Nothing AndAlso Me.originalValue <> DBNull.Value) End If Dim column As GridViewDataColumn = (DirectCast(Me.OwnerElement, GridDataCellElement)).ColumnInfo If column.DataTypeConverter IsNot Nothing AndAlso column.DataTypeConverter.CanConvertTo(Me.OwnerElement, GetType(Decimal)) Then Return Not column.DataTypeConverter.ConvertTo(Me.OwnerElement, column.FormatInfo, Me.originalValue, GetType(Decimal)).Equals(Convert.ToDecimal(Me.Value)) End If Return Not Convert.ToDecimal(Me.originalValue).Equals(Convert.ToDecimal(Me.Value)) End Get End Property End Class Private Sub RadGridView_EditorRequired(sender As Object, e As EditorRequiredEventArgs) Handles RadGridView1.EditorRequired e.EditorType = GetType(MyEditor) End Sub
All event handlers should be made virtual. All controls should be public or have properties.
To reproduce: private void Form2_Load(object sender, EventArgs e) { this.productsTableAdapter.Fill(this.nwindDataSet.Products); this.categoriesTableAdapter.Fill(this.nwindDataSet.Categories); this.radGridView1.AutoGenerateHierarchy = true; this.radGridView1.DataSource = this.nwindDataSet; this.radGridView1.DataMember = "Categories"; this.radGridView1.MasterTemplate.AutoSizeColumnsMode = GridViewAutoSizeColumnsMode.Fill; this.radGridView1.MasterTemplate.Templates.First().AutoSizeColumnsMode = GridViewAutoSizeColumnsMode.Fill; GridViewSummaryItem summaryItem = new GridViewSummaryItem(); summaryItem.Name = "CategoryID"; summaryItem.Aggregate = GridAggregateFunction.Count; GridViewSummaryRowItem summaryRowItem = new GridViewSummaryRowItem(); summaryRowItem.Add(summaryItem); this.radGridView1.SummaryRowsTop.Add(summaryRowItem); GridViewSummaryItem summaryItem2 = new GridViewSummaryItem(); summaryItem2.Name = "UnitPrice"; summaryItem2.Aggregate = GridAggregateFunction.Sum; GridViewSummaryRowItem summaryRowItem2 = new GridViewSummaryRowItem(); summaryRowItem2.Add(summaryItem2); this.radGridView1.MasterTemplate.Templates.First().SummaryRowsTop.Add(summaryRowItem2); } private void SetNumberFormat() { this.radGridView1.Columns["CategoryID"].FormatString = "{0:F4}"; this.radGridView1.SummaryRowsTop[0][0].FormatString = "{0:F4}"; this.radGridView1.MasterTemplate.Templates.First().Columns["UnitPrice"].FormatString = "{0:F4}"; this.radGridView1.MasterTemplate.Templates.First().SummaryRowsTop[0][0].FormatString = "{0:F4}"; } private void radButton1_Click(object sender, EventArgs e) { SetNumberFormat(); } Workaround: Clear and add back the summary rows when a value in the child template is changed. private void radButton1_Click(object sender, EventArgs e) { this.radGridView1.MasterTemplate.Templates.First().SummaryRowsTop.Clear(); GridViewSummaryItem summaryItem2 = new GridViewSummaryItem(); summaryItem2.Name = "UnitPrice"; summaryItem2.Aggregate = GridAggregateFunction.Sum; GridViewSummaryRowItem summaryRowItem2 = new GridViewSummaryRowItem(); summaryRowItem2.Add(summaryItem2); this.radGridView1.MasterTemplate.Templates.First().SummaryRowsTop.Add(summaryRowItem2); SetNumberFormat(); }
Workaround: use custom editor element private void radGridView1_EditorRequired(object sender, EditorRequiredEventArgs e) { if (e.EditorType == typeof(RadMultiColumnComboBoxElement)) { e.EditorType = typeof(MyRadMultiColumnComboBoxElement); } } public class MyRadMultiColumnComboBoxElement : RadMultiColumnComboBoxElement { protected override Type ThemeEffectiveType { get { return typeof(RadMultiColumnComboBoxElement); } } protected override void ProcessKeyDown(object sender, KeyEventArgs e) { base.ProcessKeyDown(sender, e); FieldInfo fi = this.GetType().BaseType.BaseType.GetField("oldTextValue", BindingFlags.Instance | BindingFlags.NonPublic); fi.SetValue(this, this.textBox.Text.Substring(0, this.textBox.SelectionStart)); } }
To reproduce: 1. Add a RadGridView with a GridViewMultiComboBoxColumn. Enable the auto filter functionality for this column and add an appropriate FilterDescriptor to the RadMultiColumnComboBoxElement. 2. Using the keyboard arrows only (no mouse), navigate to the GridViewMultiComboBoxColumn. 3. Type "ba" by using the keyboard. The "b" is lost and only the "a" gets to the filter. I expect the filter to show "ba". Workaround: use custom row behavior public Form1() { InitializeComponent(); //register the custom row behavior BaseGridBehavior gridBehavior = radGridView1.GridBehavior as BaseGridBehavior; gridBehavior.UnregisterBehavior(typeof(GridViewDataRowInfo)); gridBehavior.RegisterBehavior(typeof(GridViewDataRowInfo), new CustomGridDataRowBehavior()); } public class CustomGridDataRowBehavior : GridDataRowBehavior { protected override bool ProcessAlphaNumericKey(KeyPressEventArgs keys) { bool result = base.ProcessAlphaNumericKey(keys); if (this.IsInEditMode && (this.BeginEditMode == RadGridViewBeginEditMode.BeginEditOnKeystroke || this.BeginEditMode == RadGridViewBeginEditMode.BeginEditOnKeystrokeOrF2)) { if (this.GridViewElement.ActiveEditor is RadMultiColumnComboBoxElement) { this.GridViewElement.ActiveEditor.Value = keys.KeyChar; if (this.GridViewElement.IsInEditMode) { RadMultiColumnComboBoxElement mccb = (RadMultiColumnComboBoxElement)this.GridViewElement.ActiveEditor; RadTextBoxItem textBoxItem = mccb.TextBoxElement.TextBoxItem; textBoxItem.Clear(); textBoxItem.Text = keys.KeyChar.ToString(); textBoxItem.SelectionStart = 1; textBoxItem.SelectionLength = 0; } return true; } } return result; } }
To reproduce: public abstract class Base { public abstract string Name { get; } } public class Child : Base { public override string Name { get { return "Child"; } } } public class Child2 : Base { public override string Name { get { return "Child2"; } } } public partial class RadForm1 : Telerik.WinControls.UI.RadForm { public RadForm1() { InitializeComponent(); var list = new List<Base>(); list.Add(new Child()); list.Add(new Child()); list.Add(new Child2()); radGridView1.DataSource = list.ToArray(); } } Workaround: radGridView1.DataSource = list;
Workaround: skip the summary rows by creating custom GridViewSearchRowInfo: private void radGridView1_CreateRowInfo(object sender, GridViewCreateRowInfoEventArgs e) { if (e.RowInfo is GridViewSearchRowInfo) { e.RowInfo = new CustomGridViewSearchRowInfo(e.ViewInfo); } } public class CustomGridViewSearchRowInfo : GridViewSearchRowInfo { public CustomGridViewSearchRowInfo(GridViewInfo viewInfo) : base(viewInfo) { } protected override bool MatchesSearchCriteria(string searchCriteria, GridViewRowInfo row, GridViewColumn col) { if (row is GridViewSummaryRowInfo) { return false; } return base.MatchesSearchCriteria(searchCriteria, row, col); } }
To reproduce: radGridView1.GridNavigator.SelectFirstRow(); for (int i = 0; i < radGridView1.RowCount; i++) { var result = radGridView1.GridNavigator.SelectNextRow(1); } Workaround: - Move to the last row first: radGridView1.GridNavigator.SelectLastRow();
I've attached a sample project. Here are the steps to repeat this issue: 1. Run the application 2. Click column A and drag it to the right to reorder it, scrolling the window as it goes 3. You are eventually presented with a NullReferenceException You may have to try this several times with different columns before the problem manifests. I have found that moving just beyond the right edge of the main form and moving the mouse cursor up and down a little helps. I appears this problem only occurs in grids with many columns, so that fast scrolling can occur for multiple seconds when reordering columns. Workaround: Sub New() InitializeComponent() Me.RadGridView1.GridViewElement.RegisterService(New MyRadGridViewDragDropService(Me.RadGridView1.GridViewElement)) End Sub Public Class MyRadGridViewDragDropService Inherits RadGridViewDragDropService Public Sub New(gridViewElement As RadGridViewElement) MyBase.New(gridViewElement) End Sub Public Overrides ReadOnly Property Name As String Get Return "RadGridViewDragDropService" End Get End Property Protected Overrides Sub PrepareDragHint(dropTarget As Telerik.WinControls.ISupportDrop) Dim dragDropBehavior As IGridDragDropBehavior = Me.GetDragDropBehavior() If dragDropBehavior Is Nothing OrElse dragDropBehavior.DragHint Is Nothing _ OrElse dragDropBehavior.DragHint.Image Is Nothing Then Return End If Dim dropTargetItem As RadItem = TryCast(dropTarget, RadItem) If dropTargetItem IsNot Nothing AndAlso dropTargetItem.ElementTree IsNot Nothing _ AndAlso Not dropTargetItem.ElementTree.Control.Equals(Me.GridViewElement.ElementTree.Control) Then Return End If dragDropBehavior.UpdateDropContext(TryCast(Me.Context, ISupportDrag), dropTarget, Me.beginPoint) Dim hintSize As Size = dragDropBehavior.GetDragHintSize(dropTarget) Dim image As New Bitmap(hintSize.Width, hintSize.Height) Dim temp As Graphics = Graphics.FromImage(image) dragDropBehavior.DragHint.Paint(temp, New RectangleF(PointF.Empty, hintSize)) temp.Dispose() Dim dragHintWindow As New RadLayeredWindow() GetType(RadGridViewDragDropService).GetField("dragHintWindow", _ Reflection.BindingFlags.NonPublic Or Reflection.BindingFlags.Instance).SetValue(Me, dragHintWindow) dragHintWindow.BackgroundImage = image End Sub End Class
To reproduce: use the following code snippet. From the filtering box, when you select "Null" and then select "All", the following error occurs: Item has already been added. Key in dictionary: '(Blanks)' Key being added: '(Blanks)' DataTable dt = new DataTable(); dt.Columns.Add("Id", typeof(int)); dt.Columns.Add("Name", typeof(string)); dt.Rows.Add(1,"A"); dt.Rows.Add(2, ""); dt.Rows.Add(3, null); dt.Rows.Add(4, "B"); dt.Rows.Add(5, "C"); dt.Rows.Add(6, ""); this.radGridView1.DataSource = dt; this.radGridView1.AutoSizeColumnsMode = Telerik.WinControls.UI.GridViewAutoSizeColumnsMode.Fill; this.radGridView1.EnableFiltering = true; this.radGridView1.ShowFilteringRow = false; this.radGridView1.ShowHeaderCellButtons = true; Workaround: this.radGridView1.FilterPopupInitialized += radGridView1_FilterPopupInitialized; RadListFilterDistinctValuesTable selectedValues; private void radGridView1_FilterPopupInitialized(object sender, Telerik.WinControls.UI.FilterPopupInitializedEventArgs e) { RadListFilterPopup popup = e.FilterPopup as RadListFilterPopup; selectedValues = popup.MenuTreeElement.SelectedValues; popup.MenuTreeElement.TreeView.NodeCheckedChanged += TreeView_NodeCheckedChanged; } private void TreeView_NodeCheckedChanged(object sender, TreeNodeCheckedEventArgs e) { if (e.Node.CheckState == Telerik.WinControls.Enumerations.ToggleState.Off) { if (selectedValues.Contains(e.Node.Text)) { selectedValues.Remove(e.Node.Text); } } }
To reproduce: - Add an expression column with nullable type as a data source. - Open the property builder. Workaround: Set the data type at run time.
To reproduce: - Add some columns to the grid, make sure that most of the columns are not visible (the user must scroll to view them). - Drag and drop the second column at the last position in the grid. - The result can be seen on the attached image. Workaround: Private Sub Columns_CollectionChanged(ByVal sender As Object, ByVal e As Telerik.WinControls.Data.NotifyCollectionChangedEventArgs) Me.RadGridView1.TableElement.ViewElement.UpdateRowsWhenColumnsChanged() End Sub
To reproduce: public Form1() { InitializeComponent(); BindingList<Item> items = new BindingList<Item>(); for (int i = 0; i < 30; i++) { if (i % 3 == 0) { items.Add(new Item(i,"Item" + i, IndeterminateBoolean.YesAndNo)); } else if (i % 3 == 1) { items.Add(new Item(i, "Item" + i, IndeterminateBoolean.Yes)); } else { items.Add(new Item(i, "Item" + i, IndeterminateBoolean.No)); } } this.radGridView1.DataSource = items; this.radGridView1.AutoSizeColumnsMode = GridViewAutoSizeColumnsMode.Fill; this.radGridView1.EnableFiltering = true; this.radGridView1.ShowHeaderCellButtons = true; this.radGridView1.ShowFilteringRow = false; } public class Item { public int Id { get; set; } public string Name { get; set; } public IndeterminateBoolean IsActive { get; set; } public Item(int id, string name, IndeterminateBoolean isActive) { this.Id = id; this.Name = name; this.IsActive = isActive; } } public enum IndeterminateBoolean { No, Yes, YesAndNo } Workaround: use custom filtering http://docs.telerik.com/devtools/winforms/gridview/filtering/custom-filtering
To reproduce: public Form1() { InitializeComponent(); BindingList<Item> items = new BindingList<Item>(); for (int i = 0; i < 30; i++) { if (i % 3 == 0) { items.Add(new Item(i,"Item" + i, IndeterminateBoolean.YesAndNo)); } else if (i % 3 == 1) { items.Add(new Item(i, "Item" + i, IndeterminateBoolean.Yes)); } else { items.Add(new Item(i, "Item" + i, IndeterminateBoolean.No)); } } this.radGridView1.DataSource = items; GridViewCheckBoxColumn checkBox = new GridViewCheckBoxColumn("CheckBoxCol"); checkBox.DataTypeConverter = new IndeterminateBooleanToggleStateConverter(); checkBox.FieldName = "IsActive"; checkBox.ThreeState = true; this.radGridView1.Columns.Add(checkBox); this.radGridView1.AutoSizeColumnsMode = GridViewAutoSizeColumnsMode.Fill; this.radGridView1.EnableFiltering = true; this.radGridView1.ShowHeaderCellButtons = true; this.radGridView1.ShowFilteringRow = false; } public class Item { public int Id { get; set; } public string Name { get; set; } public IndeterminateBoolean IsActive { get; set; } public Item(int id, string name, IndeterminateBoolean isActive) { this.Id = id; this.Name = name; this.IsActive = isActive; } } public enum IndeterminateBoolean { No, Yes, YesAndNo } public class IndeterminateBooleanToggleStateConverter : TypeConverter { public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) { return sourceType == typeof(ToggleState); } public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) { return destinationType == typeof(ToggleState); } public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) { if (value is ToggleState) { switch ((ToggleState)value) { case ToggleState.On: return IndeterminateBoolean.Yes; case ToggleState.Off: return IndeterminateBoolean.No; case ToggleState.Indeterminate: default: return IndeterminateBoolean.YesAndNo; } } else { return base.ConvertFrom(context, culture, value); } } public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) { if (destinationType == typeof(ToggleState)) { if (value is IndeterminateBoolean) { switch ((IndeterminateBoolean)value) { case IndeterminateBoolean.Yes: return ToggleState.On; case IndeterminateBoolean.No: return ToggleState.Off; case IndeterminateBoolean.YesAndNo: default: return ToggleState.Indeterminate; } } if (value is string) { switch (((string)value ?? string.Empty).Trim()) { case "Yes": return ToggleState.On; case "No": case "": return ToggleState.Off; case "Both": default: return ToggleState.Indeterminate; } } else { return base.ConvertTo(context, culture, value, destinationType); } } else { return base.ConvertTo(context, culture, value, destinationType); } } } Workaround: use the custom filtering functionality: http://docs.telerik.com/devtools/winforms/gridview/filtering/custom-filtering You can access the RadGridView.FilterDescriptors collection and according to the FilterDescriptor.Expression property to determine whether the row will be visible or not.
To reproduce: - Create load on demand hierarchy. - Open the excel filter popup. - The RowSourceNeeded event fires for all rows. Workaround: public class MyGridHeaderCellElement : GridHeaderCellElement { public MyGridHeaderCellElement(GridViewDataColumn col, GridRowElement row) : base(col, row) { } protected override Type ThemeEffectiveType { get { return typeof(GridHeaderCellElement); } } protected override IGridFilterPopup CreateFilterPopup() { this.GridControl.Tag = "FileterInitializing"; return base.CreateFilterPopup(); } } // in the main forms you cab skip the event code execution while the popup is initialized private void RadGridView1_FilterPopupInitialized(object sender, FilterPopupInitializedEventArgs e) { this.radGridView1.Tag = null; } private void RadGridView1_CreateCell(object sender, GridViewCreateCellEventArgs e) { if (object.ReferenceEquals(e.CellType, typeof(GridHeaderCellElement))) { e.CellType = typeof(MyGridHeaderCellElement); } } void radGridView1_RowSourceNeeded(object sender, GridViewRowSourceNeededEventArgs e) { if (radGridView1.Tag != null && radGridView1.Tag == "FileterInitializing") { return; } //other code }
The behavior should be consistent no matter if you change the current column or the current row.
To reproduce: Add the following view: for (int i = 0; i < 8; i++) { radGridView2.Columns.Add("Col" + (i+1)); } ColumnGroupsViewDefinition view = new ColumnGroupsViewDefinition(); view.ColumnGroups.Add(new GridViewColumnGroup("G1")); view.ColumnGroups.Add(new GridViewColumnGroup("G2")); view.ColumnGroups.Add(new GridViewColumnGroup("G3")); view.ColumnGroups[0].Rows.Add(new GridViewColumnGroupRow()); view.ColumnGroups[0].Rows[0].ColumnNames.Add("Col1"); view.ColumnGroups[0].Rows[0].ColumnNames.Add("Col2"); view.ColumnGroups[0].Rows[0].ColumnNames.Add("Col3"); view.ColumnGroups[1].Rows.Add(new GridViewColumnGroupRow()); view.ColumnGroups[1].Rows[0].ColumnNames.Add("Col4"); view.ColumnGroups[1].Rows[0].ColumnNames.Add("Col5"); view.ColumnGroups[2].Rows.Add(new GridViewColumnGroupRow()); view.ColumnGroups[2].Rows[0].ColumnNames.Add("Col6"); view.ColumnGroups[2].Rows[0].ColumnNames.Add("Col7"); view.ColumnGroups[2].Rows[0].ColumnNames.Add("Col8"); radGridView2.ViewDefinition = view; for (int i = 0; i < 10; i++) { radGridView2.Rows.Add("row"+i, "test","test","test","test","test","test"); } radGridView2.Columns[2].IsVisible = false; radGridView2.Columns[7].IsVisible = false; - Then export the grid with the spread exporter.
To reproduce: use the following code snippet. You will notice that the "Accounting Manager" group is missing. private void Form1_Load(object sender, EventArgs e) { this.customersTableAdapter.Fill(this.nwindDataSet.Customers); this.radGridView1.DataSource = this.customersBindingSource; 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].ColumnNames.Add("CompanyName"); view.ColumnGroups[0].Rows[0].ColumnNames.Add("ContactName"); view.ColumnGroups[0].Rows[0].ColumnNames.Add("ContactTitle"); view.ColumnGroups[1].Groups[0].Rows.Add(new GridViewColumnGroupRow()); view.ColumnGroups[1].Groups[0].Rows[0].ColumnNames.Add("Address"); view.ColumnGroups[1].Groups[0].Rows[0].ColumnNames.Add("City"); view.ColumnGroups[1].Groups[0].Rows[0].ColumnNames.Add("Country"); view.ColumnGroups[1].Groups[1].Rows.Add(new GridViewColumnGroupRow()); view.ColumnGroups[1].Groups[1].Rows[0].ColumnNames.Add("Phone"); view.ColumnGroups[1].Groups[1].Rows[0].ColumnNames.Add("Fax"); radGridView1.ViewDefinition = view; GroupDescriptor descriptor = new GroupDescriptor(); descriptor.GroupNames.Add("ContactTitle", ListSortDirection.Ascending); this.radGridView1.GroupDescriptors.Add(descriptor); this.radGridView1.Groups[0].GroupRow.IsPinned = true; }