Use attached to reproduce. Workaround: class MyGridCheckBoxHeaderCellElement : GridCheckBoxHeaderCellElement { public MyGridCheckBoxHeaderCellElement(GridRowElement row, GridViewColumn col) : base(col, row) { } bool suspenUpdate = false; protected override void checkbox_ToggleStateChanged(object sender, StateChangedEventArgs args) { suspenUpdate = true; base.checkbox_ToggleStateChanged(sender, args); suspenUpdate = false; } protected override void SetCheckBoxState() { if (!suspenUpdate) { base.SetCheckBoxState(); } } } private void RadGridView1_CreateCell(object sender, GridViewCreateCellEventArgs e) { if (e.Column != null&& e.CellType == typeof(GridCheckBoxHeaderCellElement)) { e.CellElement = new MyGridCheckBoxHeaderCellElement(e.Row, e.Column); } }
In self-reference if you bind the grid to a record having is ParentId the same as its Id, the grid will try to create a row which is parented by itself. This is not valid input data and we should throw a proper exception, otherwise the application will freeze. How to reproduce: public partial class Form2 : Form { private BindingList<DataObject> data; public Form2() { InitializeComponent(); this.radGridView1.AutoGenerateHierarchy = true; this.data = new BindingList<DataObject>(); int count = 10; for (int i = 0; i < count; i++) { DataObject p = new DataObject(); p.Id = i; p.Name = "Parent " + i; this.data.Add(p); for (int j = 0; j < count; j++) { DataObject c = new DataObject(); c.Id = count + j + i * count; c.Name = "Child " + i; c.ParentId = i; this.data.Add(c); } } this.radButton1.Click += RadButton1_Click; } private void RadButton1_Click(object sender, EventArgs e) { if (this.radGridView1.Relations.Count > 0) { this.radGridView1.Relations.Clear(); } this.radGridView1.DataSource = this.data; this.radGridView1.Relations.AddSelfReference(this.radGridView1.MasterTemplate, "Id", "ParentId"); } } public class DataObject { public int Id { get; set; } public string Name { get; set; } public int ParentId { get; set; } } Workaround: set the ParentId of the parent records int count = 10; for (int i = 0; i < count; i++) { DataObject p = new DataObject(); p.Id = i; p.Name = "Parent " + i; p.ParentId = -1; this.data.Add(p); for (int j = 0; j < count; j++) { DataObject c = new DataObject(); c.Id = count + j + i * count; c.Name = "Child " + i; c.ParentId = i; this.data.Add(c); } }
How to reproduce: check the code snippet below and the attached video. public partial class Form1 : Form { public Form1() { InitializeComponent(); this.SetupGrid(); this.radGridView1.Dock = DockStyle.Fill; this.radGridView1.UseScrollbarsInHierarchy = true; } private void SetupGrid() { BindingList<Teacher> teachers = new BindingList<Teacher>(); BindingList<Student> students = new BindingList<Student>(); for (int i = 1; i <= 2; i++) { teachers.Add(new Teacher { TeacherId = i, TeacherFirstName = "FirstName " + i, TeacherLastName = "FirstName " + i, }); for (int j = 1; j <= 3; j++) { students.Add(new Student { SudentId = j, TeacherId = i, SudentFirstName = "Student " + j, SudentLastName = "LastName " + j, }); } } this.radGridView1.Templates.Clear(); this.radGridView1.DataSource = null; this.radGridView1.DataSource = teachers; this.radGridView1.AutoSizeColumnsMode = GridViewAutoSizeColumnsMode.Fill; GridViewTemplate template = new GridViewTemplate(); template.AutoSizeColumnsMode = GridViewAutoSizeColumnsMode.Fill; template.DataSource = students; this.radGridView1.MasterTemplate.Templates.Add(template); GridViewRelation relation = new GridViewRelation(radGridView1.MasterTemplate); relation.ChildTemplate = template; relation.RelationName = "TeacherStudents"; relation.ParentColumnNames.Add("TeacherId"); relation.ChildColumnNames.Add("TeacherId"); this.radGridView1.Relations.Add(relation); this.radGridView1.ChildViewExpanded += RadGridView1_ChildViewExpanded1; } private void RadGridView1_ChildViewExpanded1(object sender, ChildViewExpandedEventArgs e) { } private void radButton1_Click(object sender, EventArgs e) { this.radGridView1.SaveLayout("..\\..\\save.xml"); } private void radButton2_Click(object sender, EventArgs e) { this.radGridView1.LoadLayout("..\\..\\save.xml"); } } public class Teacher { public int TeacherId { get; set; } public string TeacherFirstName { get; set; } public string TeacherLastName { get; set; } } public class Student { public int SudentId { get; set; } public int TeacherId { get; set; } public string SudentFirstName { get; set; } public string SudentLastName { get; set; } } Workaround: prevent the child templates from serializing public class MyRadGridView : RadGridView { public override string ThemeClassName { get { return typeof(RadGridView).FullName; } } public override void SaveLayout(string fileName) { MyGridViewLayoutSerializer ser = new MyGridViewLayoutSerializer(this.XmlSerializationInfo); using (XmlTextWriter writer = new XmlTextWriter(fileName, Encoding.UTF8)) { writer.Formatting = Formatting.Indented; writer.WriteStartElement("RadGridView"); ser.WriteObjectElement(writer, this); } } } public class MyGridViewLayoutSerializer : GridViewLayoutSerializer { public MyGridViewLayoutSerializer(ComponentXmlSerializationInfo componentSerializationInfo) : base(componentSerializationInfo) { } protected override bool ShouldSerializeValue(object component, PropertyDescriptor property, PropertySerializationMetadata overwriteMetadata) { if (property.Name == "Templates") { return false; } return base.ShouldSerializeValue(component, property, overwriteMetadata); } }
To reproduce: please refer to the attached gif file and sample project Workaround: set the AutoSizeRows property to false
The scenario which should be covered is selecting some data from Excel and pasting in the new row of RadGridView. This is an easy way for inserting data in the grid.
How to reproduce: public partial class Form1 : Form { public Form1() { InitializeComponent(); this.radGridView1.DataSource = this.GetData(); this.radGridView1.EditorRequired += RadGridView1_EditorRequired; } private void RadGridView1_EditorRequired(object sender, EditorRequiredEventArgs e) { if (this.radGridView1.CurrentColumn.Index == 0) { e.Editor = new RadTimePickerElement(); } } private DataTable GetData() { DataTable dt = new DataTable(); dt.Columns.Add("Date", typeof(DateTime)); for (int i = 0; i < 20; i++) { DataRow r = dt.NewRow(); dt.Rows.Add(r); } return dt; } } Workaround: the scenario is not completely valid as when handling the EditorRequiredEvent one should use the GridTimePickerEditor 1. Use the column`s EditorType property: ((GridViewDateTimeColumn)this.radGridView1.Columns["Date"]).EditorType = GridViewDateTimeEditorType.TimePicker 2. Alternatively, handle the event this way: private void RadGridView1_EditorRequired(object sender, EditorRequiredEventArgs e) { if (this.radGridView1.CurrentColumn.Index == 0) { e.Editor = new GridTimePickerEditor(); } }
Use attached to reproduce. - Check the filter box - Uncheck the header checkbox. - The cells are still visible and you cannot click on the data check boxes.
Use attached to reproduce. Workaround: class MyDataCellElement : GridDataCellElement { public MyDataCellElement(GridViewColumn col, GridRowElement row) : base(col,row) { } protected override List<CharacterRange> GetSearchHighlightRanges() { // return base.GetSearchHighlightRanges(); List<CharacterRange> ranges = new List<CharacterRange>(); if (this.ColumnInfo == null || !this.RowInfo.SearchCache.Contains(this.ColumnInfo)) { return ranges; } string criteria = this.RowInfo.SearchCache[this.ColumnInfo] as string; int index = -1; CompareOptions options; if (this.MasterTemplate.MasterViewInfo.TableSearchRow.CaseSensitive) { options = CompareOptions.Ordinal; } else { options = this.MasterTemplate.MasterViewInfo.TableSearchRow.CompareOptions; } do { if (index + 1 >= this.Text.Length) { break; } index = this.MasterTemplate.MasterViewInfo.TableSearchRow.Culture.CompareInfo.IndexOf(this.Text, criteria, index + 1, options); if (index >= 0) { var str = this.Text.Substring(index, criteria.Length); int symbolCount = 0; foreach (char ch in str) { if (!Char.IsLetterOrDigit(ch)) { symbolCount++; } } ranges.Add(new CharacterRange(index, criteria.Length + symbolCount)); } } while (index >= 0 && ranges.Count < 32); return ranges; } } private void MasterTemplate_CreateCell(object sender, GridViewCreateCellEventArgs e) { if (e.CellType == typeof(GridDataCellElement)) { e.CellElement = new MyDataCellElement(e.Column, e.Row); } }
To reproduce: run the attached sample project and click the new row. Workaround: don't call the Begin/EndUpdate methods in the CurrentRowChanged event.
This new API will be useful for implementing custom sorting scenarios when you need to have custom sorting only for a single column. A similar API is available for the filtering functionality (MasterTemplate.DataView.FilterEvaluate)
Use attached to reproduce. This is not an issue. Performing Begin/End update disposes of all elements along with the globally declared item. You need to check if the item is disposed of: void ContextMenuOpening(object sender, ContextMenuOpeningEventArgs e) { if (menuItem.IsDisposed) { menuItem = new RadMenuItem(); menuItem.Text = "Custom menu item"; menuItem.Click += menuItem_Click; } e.ContextMenu.Items.Add(menuItem); }
To reproduce: - Add 7-8 columns to the grid. - Set the AutoSizeColumnsMode to Fill - Set the MaxWidth/MaxWidth of the last two columns. - Resize the first column. - Sometimes the size of the other columns is randomly increased/decreased.
To reproduce: public RadForm1() { InitializeComponent(); this.radGridView1.EnableFiltering = true; this.radGridView1.ShowHeaderCellButtons = true; this.radGridView1.FilterPopupRequired += radGridView1_FilterPopupRequired; } private void radGridView1_FilterPopupRequired(object sender, Telerik.WinControls.UI.FilterPopupRequiredEventArgs e) { e.FilterPopup.PopupOpening -= FilterPopup_PopupOpening; e.FilterPopup.PopupOpening += FilterPopup_PopupOpening; } private void FilterPopup_PopupOpening(object sender, CancelEventArgs args) { args.Cancel = true; } Workaround: either set the ShowHeaderCellButtons property to false or closed the popup immediately after it is opened. private void radGridView1_FilterPopupRequired(object sender, Telerik.WinControls.UI.FilterPopupRequiredEventArgs e) { e.FilterPopup.PopupOpening -= FilterPopup_PopupOpening; e.FilterPopup.PopupOpening += FilterPopup_PopupOpening; } private void FilterPopup_PopupOpening(object sender, CancelEventArgs args) { RadListFilterPopup popup = sender as RadListFilterPopup; popup.PopupOpened -= popup_PopupOpened; popup.PopupOpened += popup_PopupOpened; } private void popup_PopupOpened(object sender, EventArgs args) { RadListFilterPopup popup = sender as RadListFilterPopup; popup.ClosePopup(RadPopupCloseReason.Mouse); }
How to reproduce: check the attached project Workaround: create a custom RadListFilterPopup public class MyRadListFilterPopup : RadListFilterPopup { public MyRadListFilterPopup(GridViewDataColumn dataColumn, bool groupedDateValues) : base(dataColumn, groupedDateValues) { } protected override void OnButtonOkClick(EventArgs e) { FilterOperator filterOperator = FilterOperator.IsEqualTo; IRadListFilterElement listFilterElement = (IRadListFilterElement)typeof(RadListFilterPopup).GetField("listFilterElement", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(this); RadListFilterDistinctValuesTable selectedValues = listFilterElement.SelectedValues; switch (listFilterElement.SelectedMode) { case ListFilterSelectedMode.All: filterOperator = FilterOperator.None; break; case ListFilterSelectedMode.Null: filterOperator = FilterOperator.IsNull; break; case ListFilterSelectedMode.NotNull: filterOperator = FilterOperator.IsNotNull; break; } if (filterOperator != FilterOperator.IsEqualTo) { SetFilterOperator(filterOperator); this.ClosePopup(RadPopupCloseReason.CloseCalled); } else { CompositeFilterDescriptor compositeFilterDescriptor = new CompositeFilterDescriptor(); compositeFilterDescriptor.PropertyName = this.DataColumn.Name; RadListFilterDistinctValuesTable distinctValues = this.GetDistinctValuesTable(); string blanksKey = RadGridLocalizationProvider.CurrentProvider.GetLocalizedString(RadGridStringId.FilterMenuBlanks); bool blanks = selectedValues.Contains(blanksKey); if (selectedValues.Count > distinctValues.Count / 2 && !blanks) { compositeFilterDescriptor.LogicalOperator = FilterLogicalOperator.And; foreach (DictionaryEntry entry in distinctValues) { string key = (string)entry.Key; if (string.IsNullOrEmpty(key)) { key = blanksKey; } if (!selectedValues.Contains(key)) { foreach (object value in (ArrayList)entry.Value) { FilterDescriptor descriptor; if (value == DBNull.Value) { descriptor = new FilterDescriptor(this.DataColumn.Name, FilterOperator.IsNotEqualTo, null); } else if (this.DataColumn is GridViewDateTimeColumn || this.DataColumn.DataType == typeof(DateTime) || this.DataColumn.DataType == typeof(DateTime?)) { descriptor = new DateFilterDescriptor(this.DataColumn.Name, FilterOperator.IsNotEqualTo, (DateTime?)value, false); } else { descriptor = new FilterDescriptor(this.DataColumn.Name, FilterOperator.IsNotEqualTo, value); } compositeFilterDescriptor.FilterDescriptors.Add(descriptor); } } } } else { compositeFilterDescriptor.LogicalOperator = FilterLogicalOperator.Or; foreach (DictionaryEntry entry in selectedValues) { foreach (object value in (ArrayList)entry.Value) { FilterDescriptor descriptor; if (value == DBNull.Value) { descriptor = new FilterDescriptor(this.DataColumn.Name, FilterOperator.IsNotEqualTo, null); } else if (this.DataColumn is GridViewDateTimeColumn || this.DataColumn.DataType == typeof(DateTime) || this.DataColumn.DataType == typeof(DateTime?)) { descriptor = new DateFilterDescriptor(this.DataColumn.Name, FilterOperator.IsEqualTo, (DateTime?)value, false); } else { descriptor = new FilterDescriptor(this.DataColumn.Name, FilterOperator.IsEqualTo, value); } compositeFilterDescriptor.FilterDescriptors.Add(descriptor); } } } this.FilterDescriptor = compositeFilterDescriptor; OnFilterConfirmed(); } } }
To reproduce: we have a RadPageView with two grids on two pages. The first grid has a ColumnGroupsViewDefinition applied. When you open the Property Builder and try to hide some of the columns, the error occurs. Workaround: make the changes programamtically at run time.
By default, when I am expanding a group and start sorting, the expanded group doesn't collapse. However, if you use a group comparer, all groups will always collapse, when you click a header cell to sort.