Filtering Indicators in GridView
Environment
| Product Version | 2018.2 515 |
| Product | RadGridView for WinForms |
Description
RadGridView indicates that a filter has been added to a certain column by changing the icon. At some point it may become difficult to keep track of the filtered and non-filtered columns.
Solution
The solution in the KB project will demonstrate how the columns with applied filters can be additionally highlighted by adding a separate button. The button will also present a convenient way for the end user to remove the applied filter. The header cells in the filter row will be also customized with an additional element which once clicked will remove all of the filters.
The animation below demonstrates the end result in RadGridView.
Figure 1: Filtering Indicators

1. Create a custom GridFilterCellElement and initialize a RadButtonElement in it. The layout of the cell will also need adjustments so the ArrangeOverride method of the cell will need customizations. The click event of the button will be responsible for removing the filter and the button`s visibility will by synced in the SetContentCore method.
Custom GridFilterCellElement
public class MyGridFilterCellElement : GridFilterCellElement
{
private RadButtonElement clearButtonElement;
public MyGridFilterCellElement(GridViewDataColumn column, GridRowElement row)
: base(column, row)
{
}
protected override Type ThemeEffectiveType
{
get
{
return typeof(GridFilterCellElement);
}
}
public RadButtonElement ClearButtonElement
{
get
{
return this.clearButtonElement;
}
}
protected override void CreateChildElements()
{
base.CreateChildElements();
this.clearButtonElement = new RadButtonElement();
this.clearButtonElement.Image = Properties.Resources.cross16x16;
this.clearButtonElement.Click += ClearButtonElement_Click;
this.clearButtonElement.NotifyParentOnMouseInput = false;
this.Children.Add(this.clearButtonElement);
}
protected override SizeF ArrangeOverride(SizeF finalSize)
{
SizeF size = base.ArrangeOverride(finalSize);
if (this.IsFilterApplied)
{
RectangleF arrangeRect = new RectangleF(finalSize.Width - this.FilterButton.DesiredSize.Width - this.clearButtonElement.DesiredSize.Width - this.ElementSpacing, 4,
this.clearButtonElement.DesiredSize.Width, this.clearButtonElement.DesiredSize.Height);
this.clearButtonElement.Arrange(arrangeRect);
}
if (this.ColumnInfo is GridViewDecimalColumn)
{
this.TextAlignment = ContentAlignment.MiddleLeft;
}
return size;
}
protected override void SetTextAlignment()
{
base.SetTextAlignment();
if (this.ColumnInfo is GridViewDecimalColumn)
{
this.TextAlignment = ContentAlignment.MiddleLeft;
}
}
protected override void SetContentCore(object value)
{
base.SetContentCore(value);
this.clearButtonElement.Visibility = this.DataColumnInfo.FilterDescriptor != null ? ElementVisibility.Visible : ElementVisibility.Collapsed;
}
public override bool IsCompatible(GridViewColumn data, object context)
{
return context is GridFilterRowElement;
}
private void ClearButtonElement_Click(object sender, EventArgs e)
{
this.DataColumnInfo.FilterDescriptor = null;
}
}
2. Clicking on filtering row will set the filter cell in edit mode. In our custom scenario we would like to avoid that and not enter edit mode when clicking on the newly created button. That is why we need a special row behavior class in which we can override the OnMouseDown method:
Custom GridFilterRowBehavior
public class MyGridFilterRowBehavior : GridFilterRowBehavior
{
protected override bool OnMouseDownLeft(MouseEventArgs e)
{
MyGridFilterCellElement filterCell = this.GetCellAtPoint(e.Location) as MyGridFilterCellElement;
if (filterCell != null && filterCell.ClearButtonElement.ControlBoundingRectangle.Contains(e.Location))
{
return false;
}
return base.OnMouseDownLeft(e);
}
}
3. The image in the header cell located in the filter row can be customized as well. In its virtual OnMouseDown method we will add our special logic for clearing all the filters.
Custom GridRowHeaderCellElement
public class MyGridRowHeaderCellElement : GridRowHeaderCellElement
{
private Image clearImage;
public MyGridRowHeaderCellElement(GridViewColumn column, GridRowElement row)
: base(column, row)
{
this.clearImage = Properties.Resources.cross16x16;
}
protected override Type ThemeEffectiveType
{
get
{
return typeof(GridRowHeaderCellElement);
}
}
public override bool IsCompatible(GridViewColumn data, object context)
{
return context is GridFilterRowElement;
}
protected override void UpdateImage()
{
if (this.GridControl != null && this.GridControl.FilterDescriptors.Count > 0 && !this.RowElement.IsCurrent && this.RowElement is GridFilterRowElement)
{
this.Image = this.clearImage;
return;
}
base.UpdateImage();
}
protected override void OnMouseDown(MouseEventArgs e)
{
base.OnMouseDown(e);
if (this.GridControl != null && this.GridControl.FilterDescriptors.Count > 0 && !this.RowElement.IsCurrent && this.RowElement is GridFilterRowElement)
{
this.GridControl.FilterDescriptors.Clear();
}
}
}
4. Below is the sample code demonstrating how the custom solution can be utilized. The custom cell elements can be specified in the RadGridView.CreateCell event. The custom row behavior class needs to be registered and this can be done in the form`s constructor.
Initial Setup and Events
public partial class FilteringIndicatorsForm : Telerik.WinControls.UI.RadForm
{
public FilteringIndicatorsForm()
{
InitializeComponent();
this.radGridView1.CreateCell += RadGridView1_CreateCell;
BaseGridBehavior gridBehavior = radGridView1.GridBehavior as BaseGridBehavior;
gridBehavior.UnregisterBehavior(typeof(GridViewFilteringRowInfo));
gridBehavior.RegisterBehavior(typeof(GridViewFilteringRowInfo), new MyGridFilterRowBehavior());
this.radGridView1.DataSource = this.GetData();
this.radGridView1.AutoSizeColumnsMode = Telerik.WinControls.UI.GridViewAutoSizeColumnsMode.Fill;
this.radGridView1.EnableFiltering = true;
}
private void RadGridView1_CreateCell(object sender, GridViewCreateCellEventArgs e)
{
if (e.CellType == typeof(GridFilterCellElement))
{
e.CellElement = new MyGridFilterCellElement((GridViewDataColumn)e.Column, e.Row);
}
else if (e.CellType == typeof(GridRowHeaderCellElement))
{
e.CellElement = new MyGridRowHeaderCellElement(e.Column, e.Row);
}
}
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 < 20; i++)
{
dt.Rows.Add(i, "Name " + i, DateTime.Now.AddDays(i), i % 2 == 0);
}
return dt;
}
}
A complete solution providing a C# and VB.NET project is available here.