FIX. RadGridView - exception when BestFitColumns is called during data update
1.Different naming of RadGridView templates (in the Smart tag - Relations section and in the Property Builder - Relations section) is confusing. 2.Column reordering via drag and drop in the same template. This action will change the object order of the grid. All changes are shown in the Preview section: I can select columns listed in the object tree, but cannot drag them up or down within a template. The only way I can reorder columns in the property builder appears to be by dragging them left or right in the preview pane. 3.Column moving via drag and drop from one template to another template. This action will change the object order of the grid. All changes are shown in the Preview section: I cannot move columns in the object tree from one template to another. 4.Template reordering via drag and drop. All changes are shown in the Preview section: drag and drop operation for templates in not allowed. 5.There is a right-click context menu for the object tree, with the following options: "Edit", "Expand / Collapse", "New", "Delete". Under no circumstances do the options "Edit" and "New" ever become enabled. 6.The preview pane displays a preview of the columns for the master template. When the child template is selected, the preview pane still shows a preview of the columns for the master template. As such, it is not possible to reorder columns for child templates in the preview pane. 7.When you set up the RadGridView hierarchy automatically at design time and open the Property Builder, all templates are visualized. It is possible to select/deselect columns from the different templates. It is possible to change columns names. However, when you press the OK button and close the Property Builder, try to reopen it. As a result you will notice that all columns from all child templates are selected and all columns contain the default names, no matter what changes were performed. Refer to the corresponding help article http://www.telerik.com/help/winforms/gridview-design-time-support-property-builder.html
Add the ability to filter by empty values (not null values) just like in excel.
To reproduce: 1. Add text box and check box column to the grid. Add a filter descriptor to the text box column 2. Bind it to a DataTable with some data 3. Clear the columns 4. Add the columns once again => the exception will be thrown Workaround. 1. Create the following cell element: class MyHeaderCell : GridCheckBoxHeaderCellElement { public MyHeaderCell(GridViewColumn column, GridRowElement row) : base(column, row) { } protected override bool SetCheckBoxState() { if (this.ColumnIndex == -1) { return false; } return base.SetCheckBoxState(); } } 2. Subscribe to the grid's CreateCell event 3. Put the modified cell in action: void radGridView_CreateCell(object sender, GridViewCreateCellEventArgs e) { if (e.CellType == typeof(GridCheckBoxHeaderCellElement)) { e.CellType = typeof(MyHeaderCell); } }
Steps to reproduce: 1. Add a GridViewDateTimeColumn to a grid. 2. Add rows where one or more rows should contain null as the columns value. 3. Sort the grid by the date time column. WORKAROUND: Create a custom RadGridDateTimeConverter and assign it as the column's date type converter: public class CustomRadGridDateTimeConverter : RadGridDateTimeConverter { public CustomRadGridDateTimeConverter(GridViewDateTimeColumn column) : base(column) { } public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType) { if (destinationType == typeof(DateTime) && value == null) { return DateTime.MinValue; } return base.ConvertTo(context, culture, value, destinationType); } } this.radGridView1.Columns["DateTime"].DataTypeConverter = new CustomRadGridDateTimeConverter(this.radGridView1.Columns["DateTime"] as GridViewDateTimeColumn);
The example found here http://www.telerik.com/support/kb/winforms/gridview/details/high-performance-with-radgridview-and-virtual-mode-including-filtering-sorting-and-grouping, currently does not work. There should be a way for the example virtual grid to go past the current limitation in sorting, filtering and grouping.
To reproduce: public Form1() { InitializeComponent(); List<Item> items = new List<Item>(); items.Add(new Item(1,"sample")); items.Add(new Item(2, null)); items.Add(new Item(3, "sample2")); this.radGridView1.DataSource = items; this.radGridView1.AutoSizeColumnsMode = Telerik.WinControls.UI.GridViewAutoSizeColumnsMode.Fill; this.radGridView1.EnableFiltering = true; this.radGridView1.ShowFilteringRow = false; this.radGridView1.ShowHeaderCellButtons = true; } public class Item { public int Id { get; set; } public string Description { get; set; } public Item(int id, string description) { this.Id = id; this.Description = description; } } Workaround: If possible, instead of using null value, use empty string. If not possible, you will have to employ 3 classes - MyFilterMenuTreeElement, MyFilterMenuTreeItem, MyListFilterPopup. The classes are provided in the attached project RadGridViewFiltering.zip. Once you add the classes to your project, all you have to do is to replace the default popup with the new one, in the FilterPopupRequired handler: private void RadGridView1_FilterPopupRequired(object sender, FilterPopupRequiredEventArgs e) { if (e.FilterPopup is RadListFilterPopup) { e.FilterPopup = new MyListFilterPopup(e.Column); } } The approach is also demonstrated in the attached project.
To reproduce: - Assing context menu using one of the default properties.
To reproduce: public Form1() { InitializeComponent(); radGridView1.Columns.Add(new GridViewTextBoxColumn("Text1")); radGridView1.Columns.Add(new GridViewTextBoxColumn("Text2")); radGridView1.Columns.Add(new GridViewTextBoxColumn("Text3")); radGridView1.Columns.Add(new GridViewTextBoxColumn("Text4")); radGridView1.Columns.Add(new GridViewTextBoxColumn("Text5")); radGridView1.Columns.Add(new GridViewTextBoxColumn("Text6")); radGridView1.Columns.Add(new GridViewTextBoxColumn("Text7")); radGridView1.Columns.Add(new GridViewTextBoxColumn("Text8")); radGridView1.Columns.Add(new GridViewDateTimeColumn("Date1")); radGridView1.Columns.Add(new GridViewDecimalColumn("Amount1")); radGridView1.Columns.Add(new GridViewDecimalColumn("Amount2")); radGridView1.Columns.Add(new GridViewDecimalColumn("Amount3")); radGridView1.Columns.Add(new GridViewDecimalColumn("Amount4")); radGridView1.Columns.Add(new GridViewDecimalColumn("Amount5")); radGridView1.Columns.Add(new GridViewDecimalColumn("Amount6")); radGridView1.DataSource = GetDataSet(); } private DataTable GetDataSet() { DataTable dt = new DataTable(); dt.Columns.Add(new DataColumn("Text1", typeof(string))); dt.Columns.Add(new DataColumn("Text2", typeof(string))); dt.Columns.Add(new DataColumn("Text3", typeof(string))); dt.Columns.Add(new DataColumn("Text4", typeof(string))); dt.Columns.Add(new DataColumn("Text5", typeof(string))); dt.Columns.Add(new DataColumn("Text6", typeof(string))); dt.Columns.Add(new DataColumn("Text7", typeof(string))); dt.Columns.Add(new DataColumn("Text8", typeof(string))); dt.Columns.Add(new DataColumn("Date1", typeof(DateTime))); dt.Columns.Add(new DataColumn("Amount1", typeof(decimal))); dt.Columns.Add(new DataColumn("Amount2", typeof(decimal))); dt.Columns.Add(new DataColumn("Amount3", typeof(decimal))); dt.Columns.Add(new DataColumn("Amount4", typeof(decimal))); dt.Columns.Add(new DataColumn("Amount5", typeof(decimal))); dt.Columns.Add(new DataColumn("Amount6", typeof(decimal))); for (int i = 1; i <= 150000; i++) { dt.Rows.Add(new object[] { "Example Text For Row " + i.ToString(), "Example Text For Row " + i.ToString(), "More Example Text For Row " + i.ToString(), "Even More Example Text For Row " + i.ToString(), "Lots More Example Text For Row " + i.ToString(), "Excessive Example Text For Row " + i.ToString(), "Extra Example Text For Row " + i.ToString(), "Random Example Text For Row " + i.ToString(), new DateTime(2015, i % 12 + 1, i % 28 + 1), i % 2 * 10000, i % 3 * 10000, i % 5 * 10000, i % 7 * 10000, i % 11 * 10000, i % 13 * 10000 }); } return dt; } string fileName = @"..\..\" + DateTime.Now.ToLongTimeString().Replace(":", "_"); private void button1_Click(object sender, EventArgs e) { SaveFileDialog sfdExportToExcel = new SaveFileDialog(); DialogResult exportBrowse = sfdExportToExcel.ShowDialog(); if (exportBrowse == DialogResult.OK) { GridViewSpreadExport exporter = new GridViewSpreadExport(this.radGridView1); exporter.SheetMaxRows = Telerik.WinControls.UI.Export.ExcelMaxRows._1048576; exporter.FileExportMode = FileExportMode.CreateOrOverrideFile; exporter.ExportVisualSettings = false; exporter.AsyncExportCompleted += exporter_AsyncExportCompleted; SpreadExportRenderer renderer = new SpreadExportRenderer(); exporter.RunExportAsync(fileName, renderer); } }
To reproduce: - Add some rows to a grid. - Sort the rows. - Delete a row. - The current row is not the next row. Workaround: Dim t As Test = RadGridView1.CurrentRow.DataBoundItem Dim index As Integer = Me.RadGridView1.ChildRows.IndexOf(Me.RadGridView1.CurrentRow) datasource.Remove(t) Me.RadGridView1.CurrentRow = Me.RadGridView1.ChildRows(index)
To reproduce: follow the steps defined in the following help article: http://docs.telerik.com/devtools/winforms/gridview/hierarchical-grid/tutorial-binding-to-hierarchical-data Then, add a nested template in the second level. After closing the GridViewTemplate Collection Editor, you will notice that the template is not saved. http://screencast.com/t/7VDYiopuUHn Workaround: setup the hierarchy programmatically : http://docs.telerik.com/devtools/winforms/gridview/hierarchical-grid/binding-to-hierarchical-data-programmatically
To reproduce: private void Form1_Load(object sender, EventArgs e) { this.productsTableAdapter.Fill(this.nwindDataSet.Products); this.categoriesTableAdapter.Fill(this.nwindDataSet.Categories); this.radGridView1.AutoGenerateColumns = false; this.radGridView1.DataSource = this.productsBindingSource; GridViewComboBoxColumn col = new GridViewComboBoxColumn(); col.DataSource = this.categoriesBindingSource; col.MinWidth = 200; col.DisplayMember = "Description"; col.ValueMember = "CategoryID"; this.radGridView1.Columns.Add(col); this.radGridView1.AutoSizeColumnsMode = GridViewAutoSizeColumnsMode.Fill; this.radGridView1.CellValueChanged += radGridView1_CellValueChanged; } private void radGridView1_CellValueChanged(object sender, GridViewCellEventArgs e) { string value = "{nothing}"; if (e.Value != null) { value = Convert.ToString(e.Value); } RadMessageBox.Show("CellValueChanged. Value >> " + value); } Note: if the cell value is not null, the CellValueChanged event is not fired when the selection in drop down is not changed. Additional scenario: if you use a RadMultiColumnComboBoxElement for this column replaced in the EditorRequired, the issue is reproducible again.
Repeat the master template headers right after the end of an expanded detail template. The purpose is clarity for the end user.
Workaround: public partial class Form1 : Form { public Form1() { InitializeComponent(); this.radGridView1.DataSource = this.GetData(); this.radGridView1.AutoSizeColumnsMode = GridViewAutoSizeColumnsMode.Fill; ((GridViewDateTimeColumn)this.radGridView1.Columns["Date"]).FormatString = "{0: yyyy-MM-dd hh:mm:ss.fff tt}"; } private DataTable GetData() { DataTable dt = new DataTable(); dt.Columns.Add("Id", typeof(int)); dt.Columns.Add("Name", typeof(string)); dt.Columns.Add("Date", typeof(DateTime)); dt.Columns.Add("Bool", typeof(bool)); for (int i = 0; i < 100; i++) { dt.Rows.Add(i, "Name " + i, DateTime.Now.AddDays(i), i % 2 == 0); } return dt; } } public class MyRadGridView : RadGridView { public override string ThemeClassName { get { return typeof(RadGridView).FullName; } } protected override RadGridViewElement CreateGridViewElement() { return new MyRadGridViewElement(); } } public class MyRadGridViewElement : RadGridViewElement { protected override Type ThemeEffectiveType { get { return typeof(MyRadGridViewElement); } } protected override MasterGridViewTemplate CreateTemplate() { return new MyMasterGridViewTemplate(); } } public class MyMasterGridViewTemplate : MasterGridViewTemplate { public override void Copy() { base.Copy(); GridViewCellInfo[] cells = null; if (this.SelectionMode == GridViewSelectionMode.CellSelect) { cells = new GridViewCellInfo[this.SelectedCells.Count]; this.SelectedCells.CopyTo(cells, 0); } else if (this.SelectionMode == GridViewSelectionMode.FullRowSelect) { GridViewDataRowInfo row = this.SelectedRows[0] as GridViewDataRowInfo; if (this.SelectedRows.Count == 1 && row.ViewTemplate.CurrentColumn != null) { cells = new GridViewCellInfo[row.Cells.Count]; for (int i = 0; i < row.Cells.Count; i++) { cells[i] = row.Cells[i]; } } } if (Clipboard.GetData(DataFormats.Text) != null) { string data = Clipboard.GetData(DataFormats.Text).ToString(); if (data != string.Empty && cells != null) { var values = data.Split(new char[] { '\t' }, StringSplitOptions.RemoveEmptyEntries); StringBuilder sb = new StringBuilder(); foreach (string value in values) { DateTime date; if (DateTime.TryParse(value, out date)) { string baseFormat = "yyyy-MM-dd HH:mm tt"; foreach (var cell in cells) { if (cell.ColumnInfo is GridViewDateTimeColumn && ((DateTime)cell.Value).ToString(baseFormat) == date.ToString(baseFormat)) { sb.Append(string.Format(((GridViewDateTimeColumn)cell.ColumnInfo).FormatString, cell.Value) + "\t"); break; } } } else { sb.Append(value + "\t"); } } Clipboard.Clear(); Clipboard.SetData(DataFormats.Text, sb.ToString()); } } } }
The specified format in the DisplayFormat attribute should be considered when automatically generating the GridViewDateTimeColumn. public RadForm1() { InitializeComponent(); List<Item> items = new List<Item>(); for (int i = 0; i < 5; i++) { items.Add(new Item(DateTime.Now.AddDays(i))); } this.radGridView1.DataSource = items; this.radGridView1.AutoSizeColumnsMode = Telerik.WinControls.UI.GridViewAutoSizeColumnsMode.Fill; } public class Item { [System.ComponentModel.DisplayName("My Date")] [System.ComponentModel.DataAnnotations.DisplayFormat(DataFormatString = "{0:MM/dd/yyyy}")] public DateTime Date { get; set; } public Item(DateTime date) { this.Date = date; } }
How to reproduce: public partial class Form1 : Form { private RadGridView grid = new RadGridView(); public Form1() { InitializeComponent(); Controls.Add(grid); grid.Dock = DockStyle.Fill; grid.DataSource = this.GetData(); } private object GetData() { DataTable dataTable = new DataTable(); dataTable.Columns.Add("Id", typeof(int)); dataTable.Columns.Add("Name", typeof(string)); dataTable.Columns.Add("Checked", typeof(bool)); for (int i = 0; i < 200; i++) { dataTable.Rows.Add(i, "Name " + i, i % 2 == 0); } return dataTable; } protected override void OnLoad(EventArgs e) { base.OnLoad(e); grid.AutoSizeColumnsMode = GridViewAutoSizeColumnsMode.Fill; GridViewCheckBoxColumn checkBoxColumn = (GridViewCheckBoxColumn)grid.Columns["Checked"]; checkBoxColumn.EnableHeaderCheckBox = true; checkBoxColumn.SortOrder = RadSortOrder.Ascending; } } Workaround: public partial class Form1 : Form { private RadGridView grid = new RadGridView(); public Form1() { InitializeComponent(); Controls.Add(grid); grid.Dock = DockStyle.Fill; grid.DataSource = this.GetData(); grid.MouseDown += grid_MouseDown; grid.MouseUp += grid_MouseUp; } private object GetData() { DataTable dataTable = new DataTable(); dataTable.Columns.Add("Id", typeof(int)); dataTable.Columns.Add("Name", typeof(string)); dataTable.Columns.Add("Checked", typeof(bool)); for (int i = 0; i < 200; i++) { dataTable.Rows.Add(i, "Name " + i, i % 2 == 0); } return dataTable; } private void grid_MouseDown(object sender, MouseEventArgs e) { RadGridView grid = (RadGridView)sender; RadCheckBoxElement cell = grid.ElementTree.GetElementAtPoint(e.Location) as RadCheckBoxElement; if (cell != null && cell.Parent is GridCheckBoxHeaderCellElement) { sw = new Stopwatch(); sw.Start(); grid.BeginUpdate(); } } Stopwatch sw; private void grid_MouseUp(object sender, MouseEventArgs e) { RadGridView grid = (RadGridView)sender; RadCheckBoxElement cell = grid.ElementTree.GetElementAtPoint(e.Location) as RadCheckBoxElement; if (cell != null && cell.Parent is GridCheckBoxHeaderCellElement) { grid.EndUpdate(); sw.Stop(); Console.WriteLine(sw.ElapsedMilliseconds); } } protected override void OnLoad(EventArgs e) { base.OnLoad(e); grid.AutoSizeColumnsMode = GridViewAutoSizeColumnsMode.Fill; GridViewCheckBoxColumn checkBoxColumn = (GridViewCheckBoxColumn)grid.Columns["Checked"]; checkBoxColumn.EnableHeaderCheckBox = true; checkBoxColumn.SortOrder = RadSortOrder.Ascending; } }
To reproduce: please refer to the attached sample project. Note that the CellValidating event is fired twice even without showing a RadMessageBox. With an MS Button the problem is not reproducible. Workaround: use the RadGridView.ValueChanging event to perform validation while the user is typing in the active editor: private void radGridView1_ValueChanging(object sender, Telerik.WinControls.UI.ValueChangingEventArgs e) { if (((string)e.NewValue) != "x") { RadMessageBox.Show("Only 'x' allowed!"); e.Cancel = true; } }
Currently, DisplayFormatType.GeneralDate, DisplayFormatType.ShortDate, DisplayFormatType.MediumDate all return culture's DateTimeFormat.ShortDatePattern. Workaround: GridViewDateTimeColumn columnDateTime = this.radGridView1.Columns["Date"] as GridViewDateTimeColumn; columnDateTime.ExcelExportType = DisplayFormatType.Custom; columnDateTime.ExcelExportFormatString = "dd/MM/yyyy hh:mm:ss";