使用 Telerik RadGridView 进行不区分大小写和变音符号的过滤
Case insensitive and diacritial marks insensitive filtering with Telerik RadGridView
标题几乎说明了一切。如何使用 Telerik RadGridView 进行不区分大小写和不区分变音符的过滤?
我发现了很多关于 Google 的可行解决方案,但是其中 none 使用起来很简单,另外,在很多情况下它改变了 RadGridView 的 UI 行为它对最终用户的吸引力较小。
多年来我的经验和技能都有所增长,所以我终于想出了一个简单易用的解决方案。它适用于 Telerik UI 适用于 WinForms 2017 R1 或更新版本,以及 Visual Studio 2015 或更新版本。
这里是帮手class,RadGridViewHelper
:
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Globalization;
using System.Linq;
using Telerik.WinControls.Data;
using Telerik.WinControls.UI;
namespace MySoftware.Helpers
{
internal static class RadGridViewHelper
{
private class CustomStringFilteringClass
{
private RadGridView RadGridView { get; }
private bool _enabled;
private ReadOnlyCollection<string> StringColumns { get; }
public CustomStringFilteringClass(RadGridView radGridView)
{
RadGridView = radGridView;
StringColumns = new ReadOnlyCollection<string>(GetStringColumns(radGridView));
}
public void Enable()
{
if (_enabled) throw new InvalidOperationException("Can't call this method twice");
_enabled = true;
RadGridView.EnableCustomFiltering = true;
RadGridView.CustomFiltering += RadGridViewOnCustomFiltering;
}
private void RadGridViewOnCustomFiltering(object sender, GridViewCustomFilteringEventArgs e)
{
if (RadGridView.FilterDescriptors.Count == 0) return;
var row = e.Row;
foreach (var stringColumn in StringColumns)
{
var filterDescriptors = RadGridView.FilterDescriptors.Where(
x => x.PropertyName == stringColumn).ToList();
if (filterDescriptors.Count != 1)
{
continue;
}
var filterDescriptor = filterDescriptors.First();
var cellValue = ((string) row.Cells[stringColumn].Value).ToLowerInvariant();
if (filterDescriptor.GetType() == typeof(CompositeFilterDescriptor))
{
if (!CompositeFilterEvaluateString((CompositeFilterDescriptor) filterDescriptor, cellValue,
RadGridView.MasterTemplate.DataView.FilterEvaluate, row))
{
e.Visible = false;
return;
}
}
else if (!FilterEvaluateString(filterDescriptor, cellValue,
RadGridView.MasterTemplate.DataView.FilterEvaluate, row))
{
e.Visible = false;
return;
}
}
var nonStringFilterDescriptors = RadGridView.FilterDescriptors.Where(
x => !StringColumns.Contains(x.PropertyName));
foreach (var filterDescriptor in nonStringFilterDescriptors)
{
if (!RadGridView.MasterTemplate.DataView.FilterEvaluate(filterDescriptor, row))
{
e.Visible = false;
return;
}
}
}
private static bool CompositeFilterEvaluateString(CompositeFilterDescriptor compositeFilterDescriptor,
string cellValue, Func<FilterDescriptor, GridViewRowInfo, bool> gridFilterEvaluate, GridViewRowInfo row)
{
switch (compositeFilterDescriptor.LogicalOperator)
{
case FilterLogicalOperator.And:
if (compositeFilterDescriptor.FilterDescriptors.Any(filterDescriptor =>
{
if (filterDescriptor.GetType() == typeof(CompositeFilterDescriptor))
return !CompositeFilterEvaluateString((CompositeFilterDescriptor) filterDescriptor,
cellValue, gridFilterEvaluate, row);
return !FilterEvaluateString(filterDescriptor, cellValue, gridFilterEvaluate, row);
}))
return false;
break;
case FilterLogicalOperator.Or:
if (compositeFilterDescriptor.FilterDescriptors.All(filterDescriptor =>
{
if (filterDescriptor.GetType() == typeof(CompositeFilterDescriptor))
return !CompositeFilterEvaluateString((CompositeFilterDescriptor) filterDescriptor,
cellValue, gridFilterEvaluate, row);
return !FilterEvaluateString(filterDescriptor, cellValue, gridFilterEvaluate, row);
}))
return false;
break;
}
return true;
}
private static bool FilterEvaluateString(FilterDescriptor filterDescriptor, string cellValue,
Func<FilterDescriptor, GridViewRowInfo, bool> gridFilterEvaluate, GridViewRowInfo row)
{
var filterDescriptorValue = ((string) filterDescriptor.Value).ToLowerInvariant();
switch (filterDescriptor.Operator)
{
case FilterOperator.Contains:
if (CultureInfo.InvariantCulture.CompareInfo.IndexOf(cellValue, filterDescriptorValue,
CompareOptions.IgnoreNonSpace) == -1)
return false;
break;
case FilterOperator.NotContains:
if (CultureInfo.InvariantCulture.CompareInfo.IndexOf(cellValue, filterDescriptorValue,
CompareOptions.IgnoreNonSpace) != -1)
return false;
break;
case FilterOperator.StartsWith:
if (!CultureInfo.InvariantCulture.CompareInfo.IsPrefix(cellValue, filterDescriptorValue,
CompareOptions.IgnoreNonSpace))
return false;
break;
case FilterOperator.EndsWith:
if (!CultureInfo.InvariantCulture.CompareInfo.IsSuffix(cellValue, filterDescriptorValue,
CompareOptions.IgnoreNonSpace))
return false;
break;
case FilterOperator.IsEqualTo:
if (String.Compare(cellValue, filterDescriptorValue, CultureInfo.InvariantCulture,
CompareOptions.IgnoreNonSpace) != 0)
return false;
break;
case FilterOperator.IsNotEqualTo:
if (String.Compare(cellValue, filterDescriptorValue, CultureInfo.InvariantCulture,
CompareOptions.IgnoreNonSpace) == 0)
return false;
break;
default:
if (!gridFilterEvaluate.Invoke(filterDescriptor, row))
return false;
break;
}
return true;
}
}
private static List<string> GetStringColumns(RadGridView radGridView)
{
var retVal = new List<string>();
foreach (var column in radGridView.Columns)
{
if (column.DataType == typeof(string))
{
retVal.Add(column.Name);
}
}
return retVal;
}
/// <summary>
/// Enables custom string filtering on <paramref name="radGridView"/>. It is case insensitive and
/// tolerates differences in diacritical marks. For example, in a "equals" comparision, the value
/// 'ëMúa' is treated as its equal to 'EmÜâ'.
/// </summary>
/// <param name="radGridView">Instance of <see cref="RadGridView"/> in which custom string filtering
/// will be enabled.</param>
public static void CustomStringFiltering(RadGridView radGridView)
{
var customFiltering = new CustomStringFilteringClass(radGridView);
customFiltering.Enable();
}
}
}
用法很简单:
RadGridViewHelper.CustomStringFiltering(radGridView);
其中 radGridView
是 class RadGridView
的实例,字符串过滤行为将更改为该实例。
我以问答的形式把它放在这里,因为鼓励在这里:It’s OK to Ask and Answer Your Own Questions - Stack Overflow Blog
希望它对某人有所帮助并节省时间和麻烦。
标题几乎说明了一切。如何使用 Telerik RadGridView 进行不区分大小写和不区分变音符的过滤?
我发现了很多关于 Google 的可行解决方案,但是其中 none 使用起来很简单,另外,在很多情况下它改变了 RadGridView 的 UI 行为它对最终用户的吸引力较小。
多年来我的经验和技能都有所增长,所以我终于想出了一个简单易用的解决方案。它适用于 Telerik UI 适用于 WinForms 2017 R1 或更新版本,以及 Visual Studio 2015 或更新版本。
这里是帮手class,RadGridViewHelper
:
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Globalization;
using System.Linq;
using Telerik.WinControls.Data;
using Telerik.WinControls.UI;
namespace MySoftware.Helpers
{
internal static class RadGridViewHelper
{
private class CustomStringFilteringClass
{
private RadGridView RadGridView { get; }
private bool _enabled;
private ReadOnlyCollection<string> StringColumns { get; }
public CustomStringFilteringClass(RadGridView radGridView)
{
RadGridView = radGridView;
StringColumns = new ReadOnlyCollection<string>(GetStringColumns(radGridView));
}
public void Enable()
{
if (_enabled) throw new InvalidOperationException("Can't call this method twice");
_enabled = true;
RadGridView.EnableCustomFiltering = true;
RadGridView.CustomFiltering += RadGridViewOnCustomFiltering;
}
private void RadGridViewOnCustomFiltering(object sender, GridViewCustomFilteringEventArgs e)
{
if (RadGridView.FilterDescriptors.Count == 0) return;
var row = e.Row;
foreach (var stringColumn in StringColumns)
{
var filterDescriptors = RadGridView.FilterDescriptors.Where(
x => x.PropertyName == stringColumn).ToList();
if (filterDescriptors.Count != 1)
{
continue;
}
var filterDescriptor = filterDescriptors.First();
var cellValue = ((string) row.Cells[stringColumn].Value).ToLowerInvariant();
if (filterDescriptor.GetType() == typeof(CompositeFilterDescriptor))
{
if (!CompositeFilterEvaluateString((CompositeFilterDescriptor) filterDescriptor, cellValue,
RadGridView.MasterTemplate.DataView.FilterEvaluate, row))
{
e.Visible = false;
return;
}
}
else if (!FilterEvaluateString(filterDescriptor, cellValue,
RadGridView.MasterTemplate.DataView.FilterEvaluate, row))
{
e.Visible = false;
return;
}
}
var nonStringFilterDescriptors = RadGridView.FilterDescriptors.Where(
x => !StringColumns.Contains(x.PropertyName));
foreach (var filterDescriptor in nonStringFilterDescriptors)
{
if (!RadGridView.MasterTemplate.DataView.FilterEvaluate(filterDescriptor, row))
{
e.Visible = false;
return;
}
}
}
private static bool CompositeFilterEvaluateString(CompositeFilterDescriptor compositeFilterDescriptor,
string cellValue, Func<FilterDescriptor, GridViewRowInfo, bool> gridFilterEvaluate, GridViewRowInfo row)
{
switch (compositeFilterDescriptor.LogicalOperator)
{
case FilterLogicalOperator.And:
if (compositeFilterDescriptor.FilterDescriptors.Any(filterDescriptor =>
{
if (filterDescriptor.GetType() == typeof(CompositeFilterDescriptor))
return !CompositeFilterEvaluateString((CompositeFilterDescriptor) filterDescriptor,
cellValue, gridFilterEvaluate, row);
return !FilterEvaluateString(filterDescriptor, cellValue, gridFilterEvaluate, row);
}))
return false;
break;
case FilterLogicalOperator.Or:
if (compositeFilterDescriptor.FilterDescriptors.All(filterDescriptor =>
{
if (filterDescriptor.GetType() == typeof(CompositeFilterDescriptor))
return !CompositeFilterEvaluateString((CompositeFilterDescriptor) filterDescriptor,
cellValue, gridFilterEvaluate, row);
return !FilterEvaluateString(filterDescriptor, cellValue, gridFilterEvaluate, row);
}))
return false;
break;
}
return true;
}
private static bool FilterEvaluateString(FilterDescriptor filterDescriptor, string cellValue,
Func<FilterDescriptor, GridViewRowInfo, bool> gridFilterEvaluate, GridViewRowInfo row)
{
var filterDescriptorValue = ((string) filterDescriptor.Value).ToLowerInvariant();
switch (filterDescriptor.Operator)
{
case FilterOperator.Contains:
if (CultureInfo.InvariantCulture.CompareInfo.IndexOf(cellValue, filterDescriptorValue,
CompareOptions.IgnoreNonSpace) == -1)
return false;
break;
case FilterOperator.NotContains:
if (CultureInfo.InvariantCulture.CompareInfo.IndexOf(cellValue, filterDescriptorValue,
CompareOptions.IgnoreNonSpace) != -1)
return false;
break;
case FilterOperator.StartsWith:
if (!CultureInfo.InvariantCulture.CompareInfo.IsPrefix(cellValue, filterDescriptorValue,
CompareOptions.IgnoreNonSpace))
return false;
break;
case FilterOperator.EndsWith:
if (!CultureInfo.InvariantCulture.CompareInfo.IsSuffix(cellValue, filterDescriptorValue,
CompareOptions.IgnoreNonSpace))
return false;
break;
case FilterOperator.IsEqualTo:
if (String.Compare(cellValue, filterDescriptorValue, CultureInfo.InvariantCulture,
CompareOptions.IgnoreNonSpace) != 0)
return false;
break;
case FilterOperator.IsNotEqualTo:
if (String.Compare(cellValue, filterDescriptorValue, CultureInfo.InvariantCulture,
CompareOptions.IgnoreNonSpace) == 0)
return false;
break;
default:
if (!gridFilterEvaluate.Invoke(filterDescriptor, row))
return false;
break;
}
return true;
}
}
private static List<string> GetStringColumns(RadGridView radGridView)
{
var retVal = new List<string>();
foreach (var column in radGridView.Columns)
{
if (column.DataType == typeof(string))
{
retVal.Add(column.Name);
}
}
return retVal;
}
/// <summary>
/// Enables custom string filtering on <paramref name="radGridView"/>. It is case insensitive and
/// tolerates differences in diacritical marks. For example, in a "equals" comparision, the value
/// 'ëMúa' is treated as its equal to 'EmÜâ'.
/// </summary>
/// <param name="radGridView">Instance of <see cref="RadGridView"/> in which custom string filtering
/// will be enabled.</param>
public static void CustomStringFiltering(RadGridView radGridView)
{
var customFiltering = new CustomStringFilteringClass(radGridView);
customFiltering.Enable();
}
}
}
用法很简单:
RadGridViewHelper.CustomStringFiltering(radGridView);
其中 radGridView
是 class RadGridView
的实例,字符串过滤行为将更改为该实例。
我以问答的形式把它放在这里,因为鼓励在这里:It’s OK to Ask and Answer Your Own Questions - Stack Overflow Blog
希望它对某人有所帮助并节省时间和麻烦。