How to reproduce: check the attached video
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
this.radGridView1.DataSource = this.GetData(1000);
this.radGridView1.AutoExpandGroups = true;
this.radGridView1.EnableFiltering = true;
this.radGridView1.EnablePaging = true;
this.radGridView1.AutoSizeColumnsMode = GridViewAutoSizeColumnsMode.Fill;
}
private DataTable GetData(int count)
{
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 < count; i++)
{
dt.Rows.Add(i,"Name " + i, DateTime.Now.AddDays(i), i % 2 == 0 ? true : false);
}
return dt;
}
}
Workaround: cancel the PageChanging event
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
this.radGridView1.DataSource = this.GetData(1000);
this.radGridView1.AutoExpandGroups = true;
this.radGridView1.EnableFiltering = true;
this.radGridView1.EnablePaging = true;
this.radGridView1.AutoSizeColumnsMode = GridViewAutoSizeColumnsMode.Fill;
timer = new Timer();
timer.Interval = 100;
timer.Tick += (sender, e) =>
{
timer.Stop();
this.shouldCancel = false;
};
this.radGridView1.PageChanging += RadGridView1_PageChanging;
this.radGridView1.CurrentRowChanged += RadGridView1_CurrentRowChanged;
}
private void RadGridView1_CurrentRowChanged(object sender, CurrentRowChangedEventArgs e)
{
this.shouldCancel = this.ShouldCancelPageChange(e.CurrentRow);
timer.Start();
}
Timer timer;
bool shouldCancel = false;
private bool ShouldCancelPageChange(GridViewRowInfo rowInfo)
{
if (this.radGridView1.TableElement.MasterTemplate != null && this.radGridView1.TableElement.MasterTemplate.EnablePaging)
{
int pageIndex = this.radGridView1.TableElement.ViewTemplate.DataView.GetItemPage(rowInfo);
if (pageIndex == this.radGridView1.TableElement.MasterTemplate.PageIndex)
{
return true;
}
}
return false;
}
private void RadGridView1_PageChanging(object sender, Telerik.WinControls.PageChangingEventArgs e)
{
e.Cancel = this.shouldCancel;
}
private DataTable GetData(int count)
{
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 < count; i++)
{
dt.Rows.Add(i,"Name " + i, DateTime.Now.AddDays(i), i % 2 == 0 ? true : false);
}
return dt;
}
}
How to reproduce: check also the attached video
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
this.radGridView1.DataSource = this.GetData();
this.radGridView1.AutoSizeColumnsMode = GridViewAutoSizeColumnsMode.Fill;
GroupDescriptor descriptor = new GroupDescriptor();
descriptor.GroupNames.Add("Name", ListSortDirection.Ascending);
this.radGridView1.GroupDescriptors.Add(descriptor);
}
private DataTable GetData()
{
DataTable dt = new DataTable();
dt.Columns.Add("Name", typeof(string));
dt.Columns.Add("Age", typeof(int));
dt.Columns.Add("Date", typeof(DateTime));
dt.Columns.Add("Bool", typeof(bool));
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 60; j++)
{
dt.Rows.Add("Name " + i, i, DateTime.Now.AddDays(i), i % 2 == 0);
}
}
return dt;
}
private void radButton1_Click(object sender, EventArgs e)
{
GridPrintStyle style = new GridPrintStyle();
style.FitWidthMode = PrintFitWidthMode.FitPageWidth;
this.radGridView1.PrintStyle = style;
RadPrintDocument doc = new RadPrintDocument();
doc.HeaderHeight = 30;
doc.HeaderFont = new Font("Arial", 12);
doc.LeftHeader = "Left Header";
doc.MiddleHeader = "Middle header";
doc.RightHeader = "Right header";
doc.AssociatedObject = this.radGridView1;
RadPrintPreviewDialog dialog = new RadPrintPreviewDialog(doc);
dialog.Show();
}
}
Workaround: create a custom GridPrintStyle class
public class MyGridPrintStyle : GridPrintStyle
{
protected override BaseGridPrintRenderer InitializePrintRenderer(RadGridView grid)
{
BaseGridPrintRenderer rend = base.InitializePrintRenderer(grid);
if (rend is TableViewDefinitionPrintRenderer)
{
return new MyTableViewDefinitionPrintRenderer(grid);
}
return rend;
}
}
public class MyTableViewDefinitionPrintRenderer : TableViewDefinitionPrintRenderer
{
public MyTableViewDefinitionPrintRenderer(RadGridView grid)
: base(grid)
{
}
protected override void PrintRowWideCell(GridViewRowInfo row, TableViewRowLayout rowLayout, GridPrintSettings settings, int currentX, int currentY, Graphics graphics)
{
int groupLevel = row.Group != null ? row.Group.Level + 1 : 0;
int indentLevel = row.HierarchyLevel + 1 - groupLevel;
Size cellSize = this.GetRowSize(row, rowLayout);
int cellX = currentX + indentLevel * settings.HierarchyIndent + rowLayout.Owner.CellSpacing;
Rectangle cellRect = new Rectangle(cellX, currentY, cellSize.Width - indentLevel * settings.HierarchyIndent, cellSize.Height);
CellPrintElement printCell = new CellPrintElement();
if (row is GridViewGroupRowInfo)
{
if (this.PrintPages.Count > 0 && !settings.PrintHierarchy)
{
cellRect.Width -= this.PrintPages[this.CurrentPrintPage].Count - 1;
}
printCell = this.CreateGroupCellPrintElement(row as GridViewGroupRowInfo);
if (printCell.Font != settings.GroupRowFont)
{
if (settings.GroupRowFont != null)
{
printCell.Font = settings.GroupRowFont;
}
else
{
settings.GroupRowFont = printCell.Font;
}
}
}
printCell.TextPadding = this.GridView.PrintStyle.CellPadding;
printCell.RightToLeft = this.GridView.RightToLeft == RightToLeft.Yes;
PrintCellFormattingEventArgs formattEventArgs = new PrintCellFormattingEventArgs(row, null, printCell);
this.OnPrintCellFormatting(formattEventArgs);
PrintCellPaintEventArgs paintEventArgs = new PrintCellPaintEventArgs(graphics, row, null, cellRect);
this.OnPrintCellPaint(paintEventArgs);
formattEventArgs.PrintCell.Paint(graphics, paintEventArgs.CellRect);
}
}
Currently the time for opening the popup for a column with 100 000 unique items including blank items is about 8s, this can be optimized.
How to reproduce:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
this.radGridView1.EnableFiltering = true;
this.radGridView1.ShowHeaderCellButtons = true;
this.radGridView1.DataSource = this.GetData();
this.radGridView1.AutoSizeColumnsMode = GridViewAutoSizeColumnsMode.Fill;
this.radGridView1.MouseDown += RadGridView1_MouseDown;
this.radGridView1.FilterPopupInitialized += RadGridView1_FilterPopupInitialized;
}
Stopwatch sw = new Stopwatch();
private void RadGridView1_MouseDown(object sender, MouseEventArgs e)
{
GridFilterButtonElement btn = this.radGridView1.ElementTree.GetElementAtPoint(e.Location) as GridFilterButtonElement;
if (btn != null)
{
sw.Start();
}
}
private void RadGridView1_FilterPopupInitialized(object sender, FilterPopupInitializedEventArgs e)
{
((RadListFilterPopup)e.FilterPopup).PopupOpened += Form1_PopupOpened;
}
private void Form1_PopupOpened(object sender, EventArgs args)
{
sw.Stop();
Console.WriteLine("Total: " + sw.ElapsedMilliseconds);
}
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 < 100000; i++)
{
dt.Rows.Add(i, "Name " + i, DateTime.Now.AddDays(i), i % 2 == 0);
}
dt.Rows.Add(1, null, DateTime.Now.AddDays(1), false);
return dt;
}
}
To reproduce:
1. Add a GridViewCheckBoxColumn with EnableHeaderCheckBox property set to true.
2. Use the TypeConverter demonstrated in the following help article: http://docs.telerik.com/devtools/winforms/gridview/columns/converting-data-types
When you run the application and try to toggle the check box in the header cell, a FormatException occurs.
Workaround: modify the TypeConverter:
public class ToggleStateConverter : TypeConverter
{
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
{
return destinationType == typeof(ToggleState);
}
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
{
char charValue = (char)value;
switch (charValue)
{
case 'Y':
return ToggleState.On;
case 'N':
return ToggleState.Off;
case 'M':
return ToggleState.Indeterminate;
}
return base.ConvertTo(context, culture, value, destinationType);
}
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
return sourceType == typeof(ToggleState) || sourceType == typeof(bool);
}
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
ToggleState state;
bool boolValue;
if (value is ToggleState)
{
state = (ToggleState)value ;
switch (state)
{
case ToggleState.On:
return 'Y';
case ToggleState.Off:
return 'N';
case ToggleState.Indeterminate:
return 'M';
}
}
else if (value is bool)
{
boolValue = (bool)value;
switch (boolValue)
{
case true:
return 'Y';
case false:
return 'N';
default:
return 'M';
}
}
return base.ConvertFrom(context, culture, value);
}
}
Create a grid with more than 20 columns and add 5K rows for example. Maximize the form and try to scroll with mouse wheel. You will notice that the scrolling performance is worse compared to the normal state of the form with less visible visual elements. Workaround: this.radGridView1.EnableFastScrolling = true; and use the scrollbar's thumb Second workaround: use paging: https://docs.telerik.com/devtools/winforms/gridview/paging/overview Thus, you will display as many rows as possible to display on the screen per page. Instead of scrolling, you will navigate through pages.
The GridViewBrowseColumn's editor could have two modes - OpenFileDialog and FolderBrowserDialog.
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.
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.
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)
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.
To reproduce: please refer to the attached gif file and sample project Workaround: set the AutoSizeRows property to false
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);
}
}
To reproduce: run the project, select the grid and press Tab. You will notice a message box for the first grid which won't be shown for the second in the popup.
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);
}
}
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);
}
}
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();
}
}
To reproduce: run the attached sample project and click the new row. Workaround: don't call the Begin/EndUpdate methods in the CurrentRowChanged event.