此方法需要通过动态Linq进行模糊查找,所以需要下载System.Linq.Dynamic的Nuget包。
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data.Linq;
using System.Linq;
using System.Linq.Dynamic;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
namespace LinqBinding
{
public class LinqBindingListView<T> : BindingList<T>, IBindingListView where T : class
{
private IList<T> OriginalList;
private string filter;
private readonly Dictionary<Type, PropertyComparer<T>> comparers = new Dictionary<Type, PropertyComparer<T>>();
private bool isSorted;
private ListSortDirection listSortDirection;
private PropertyDescriptor propertyDescriptor;
private bool isFiltering = false;
public LinqBindingListView(IBindingList list) : base(list.Cast<T>().ToList())
{
OriginalList = list as BindingList<T>;
}
public LinqBindingListView(IList<T> list) : base(list.ToList())
{
OriginalList = list;
}
public string Filter
{
get => filter;
set
{
filter = value;
isFiltering = true;
if (!string.IsNullOrWhiteSpace(filter))
{
filter = Regex.Replace(filter, @" +like +'([^']*)'", match =>
{
string v = match.Groups[1].Value;
if (v.StartsWith("%") && v.EndsWith("%"))
return $".ToLower().Contains(\"{v.Substring(1, v.Length - 2).ToLower()}\")";
else if (v.StartsWith("%"))
return $".EndsWith(\"{v.Substring(1)}\" ,StringComparison.OrdinalIgnoreCase)";
else if (v.EndsWith("%"))
return $".StartsWith(\"{v.Substring(0, v.Length - 2)}\" ,StringComparison.OrdinalIgnoreCase)";
else
return $".Equals(\"{v}\" ,StringComparison.OrdinalIgnoreCase)";
});
if (filter.Contains("'")) filter = filter.Replace("'", "\"");
List<T> items = Items.Where(filter).ToList();
Items.Clear();
items.ForEach(item => Items.Add(item));
}
else
{
Items.Clear();
OriginalList.ToList().ForEach(item => Items.Add(item));
}
isFiltering = false;
OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1));
}
}
public ListSortDescriptionCollection SortDescriptions { get; private set; }
protected virtual bool SupportsAdvancedSorting => false;
bool IBindingListView.SupportsAdvancedSorting => SupportsAdvancedSorting;
protected virtual bool SupportsFiltering => true;
bool IBindingListView.SupportsFiltering => SupportsFiltering;
protected override bool SupportsSearchingCore => true;
protected override bool SupportsSortingCore => true;
protected override bool IsSortedCore => isSorted;
protected override PropertyDescriptor SortPropertyCore => propertyDescriptor;
protected override ListSortDirection SortDirectionCore => listSortDirection;
protected override void OnListChanged(ListChangedEventArgs e)
{
if (!isFiltering)
base.OnListChanged(e);
}
protected override void InsertItem(int index, T item)
{
if (index >= Count) OriginalList.Insert(OriginalList.Count, item);
else OriginalList.Insert(OriginalList.IndexOf(base[index]), item);
base.InsertItem(index, item);
}
protected override void RemoveItem(int index)
{
OriginalList.RemoveAt(OriginalList.IndexOf(base[index]));
base.RemoveItem(index);
}
protected override void SetItem(int index, T item)
{
OriginalList[OriginalList.IndexOf(base[index])] = item;
base.SetItem(index, item);
}
public void ApplySort(ListSortDescriptionCollection sorts)
{
SortDescriptions = sorts;
foreach (ListSortDescription sort in sorts)
{
ApplySortCore(sort.PropertyDescriptor, sort.SortDirection);
}
}
protected override void ApplySortCore(PropertyDescriptor prop, ListSortDirection direction)
{
if (Items is IBindingList b)
{
b.ApplySort(prop, direction);
}
else
{
List<T> itemsList = Items as List<T>;
Type propertyType = prop.PropertyType;
if (!comparers.TryGetValue(propertyType, out PropertyComparer<T> comparer))
{
comparer = new PropertyComparer<T>(prop, direction);
comparers.Add(propertyType, comparer);
}
comparer.SetPropertyAndDirection(prop, direction);
itemsList.Sort(comparer);
propertyDescriptor = prop;
listSortDirection = direction;
isSorted = true;
}
OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1));
}
protected override void RemoveSortCore()
{
if (Items is IBindingList b)
{
b.RemoveSort();
}
else
{
isSorted = false;
propertyDescriptor = base.SortPropertyCore;
listSortDirection = base.SortDirectionCore;
OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1));
}
}
protected override int FindCore(PropertyDescriptor property, object key)
{
IList<T> list = Items;
T Item = list.FirstOrDefault(item => property.GetValue(item).ToString().Trim().Equals(key.ToString().Trim()));
return Item == null ? -1 : IndexOf(Item);
}
public void RemoveFilter() => Filter = null;
}
public class PropertyComparer<T> : IComparer<T>
{
private readonly IComparer comparer;
private PropertyDescriptor propertyDescriptor;
private int reverse;
public PropertyComparer(PropertyDescriptor property, ListSortDirection direction)
{
propertyDescriptor = property;
Type comparerForPropertyType = typeof(Comparer<>).MakeGenericType(property.PropertyType);
comparer = (IComparer)comparerForPropertyType.InvokeMember("Default", BindingFlags.Static | BindingFlags.GetProperty | BindingFlags.Public, null, null, null);
SetListSortDirection(direction);
}
#region IComparer<T> Members
public int Compare(T x, T y) => reverse * comparer.Compare(propertyDescriptor.GetValue(x), propertyDescriptor.GetValue(y));
#endregion
private void SetPropertyDescriptor(PropertyDescriptor descriptor) => propertyDescriptor = descriptor;
private void SetListSortDirection(ListSortDirection direction) => reverse = direction == ListSortDirection.Ascending ? 1 : -1;
public void SetPropertyAndDirection(PropertyDescriptor descriptor, ListSortDirection direction)
{
SetPropertyDescriptor(descriptor);
SetListSortDirection(direction);
}
}
}