C# Expression创建ICollectionView的动态多重过滤条件

ICollectionView有一个Filter属性,接受一个Predicate<object>的委托 来生成过滤视图

准备一个实体数据类

 1 /// <summary>
 2     /// 测试数据类
 3     /// </summary>
 4     public class UserDataProxy : DynamicObject
 5     {
 6         private Dictionary<string, object> _dict = new Dictionary<string, object>();
 7 
 8         public string Color { get; set; }
 9 
10         public Guid Guid { get; set; }
11 
12         public string Layer { get; set; }
13 
14         public string Length { get; set; }
15 
16         public string Name { get; set; }
17 
18         public string Type { get; set; }
19 
20         /// <summary>
21         /// 添加动态属性
22         /// </summary>
23         /// <param name="propertyName"></param>
24         /// <param name="value"></param>
25         public void AddDynamicProperty(string propertyName, object value)
26         {
27             _dict[propertyName] = value;
28         }
29 
30         public IEnumerable<string> GetAllProPertyNames()
31         {
32             var list = new List<string>()
33             {
34                 "Guid","Type","Layer","Name","Color"
35             };
36             list.AddRange(GetDynamicMemberNames());
37             return list;
38         }
39 
40         /// <summary>
41         /// 重写获取动态属性的方法
42         /// </summary>
43         /// <returns></returns>
44         public override IEnumerable<string> GetDynamicMemberNames()
45         {
46             return _dict.Keys;
47         }
48 
49         /// <summary>
50         /// 获取动态属性的方法
51         /// </summary>
52         /// <param name="propertyName"></param>
53         /// <returns></returns>
54         public object GetDynamicValue(string propertyName)
55         {
56             if (_dict.Keys.Contains(propertyName))
57             {
58                 return _dict[propertyName];
59             }
60             return null;
61         }
62 
63         public void RemoveDynamicProperty(string propertyName)
64         {
65             if (_dict.Keys.Contains(propertyName))
66             {
67                 _dict.Remove(propertyName);
68             }
69         }
70 
71         /// <summary>
72         /// 重写获取动态属性
73         /// </summary>
74         /// <param name="binder"></param>
75         /// <param name="result"></param>
76         /// <returns></returns>
77         public override bool TryGetMember(GetMemberBinder binder, out object result)
78         {
79             var key = binder.Name;
80             return _dict.TryGetValue(key, out result);
81         }
82 
83         /// <summary>
84         /// 重写设置动态属性
85         /// </summary>
86         /// <param name="binder"></param>
87         /// <param name="value"></param>
88         /// <returns></returns>
89         public override bool TrySetMember(SetMemberBinder binder, object value)
90         {
91             var key = binder.Name;
92             _dict[key] = value ?? default;
93             return true;
94         }
95     }

准备一个运算符枚举

 1 /// <summary>
 2     /// 过滤运算符枚举
 3     /// </summary>
 4     [Flags]
 5     public enum EFilterOperator
 6     {
 7         [Description("=")]
 8         Equal = 1,
 9 
10         [Description("!=")]
11         NotEqual = 2,
12 
13         [Description(">")]
14         GreaterThan = 4,
15 
16         [Description("<")]
17         LessThan = 8,
18 
19         [Description(">=")]
20         GreaterThanOrEqual = 16,
21 
22         [Description("<=")]
23         LessThanOrEqual = 32,
24 
25         [Description("s")]
26         StartsWith = 64,
27 
28         [Description("e")]
29         EndWith = 128,
30 
31         [Description("<>")]
32         Contains = 256,
33 
34         [Description("><")]
35         NotContains = 512,
36     }

准备一个表达式树辅助类

  1 /// <summary>
  2     /// 表达式辅助类
  3     /// </summary>
  4     public class ExpressionTreeHelper
  5     {
  6         /// <summary>
  7         /// 转换属性表达式 o as UserDataProxy
  8         /// </summary>
  9         /// <typeparam name="T"></typeparam>
 10         /// <param name="type"></param>
 11         /// <returns></returns>
 12         public static UnaryExpression ConvertTo<T>(ParameterExpression parameterExpression)
 13         {
 14             return Expression.TypeAs(parameterExpression, typeof(T));
 15         }
 16 
 17         /// <summary>
 18         /// 创建条件表达式 i.Name.Contains("xx")
 19         /// </summary>
 20         /// <param name="memberExpression">属性</param>
 21         /// <param name="condition">条件</param>
 22         /// <param name="content"></param>
 23         /// <returns></returns>
 24         public static Expression CreateCondition(MemberExpression memberExpression, EFilterOperator condition, string content)
 25         {
 26             if (content == null)
 27             {
 28                 return null;
 29             }
 30             var flag = double.TryParse(content, out double num);//转换数字 能够转换是数字,不能就是文本
 31 
 32             BinaryExpression exp;//二位运算符表达式
 33 
 34             Expression left;//左侧表达式
 35             ConstantExpression right;//右侧表达式
 36 
 37             if (flag)
 38             {
 39                 //把属性转换为数字 因为有的属性可能是字符串
 40                 left = Expression.Call(null, typeof(double).GetMethod("Parse", new Type[] { typeof(string) }), new Expression[] { memberExpression });
 41 
 42                 //右侧的表达式
 43                 right = Expression.Constant(num, typeof(double));
 44             }
 45             else
 46             {
 47                 //把属性转换为字符串
 48                 left = Expression.Call(memberExpression, typeof(string).GetMethod("ToString", new Type[] { }), new Expression[] { });
 49 
 50                 //右侧的表达式
 51                 right = Expression.Constant(content, typeof(string));
 52             }
 53 
 54             MethodCallExpression callExp;
 55             switch (condition)
 56             {
 57                 case EFilterOperator.Equal:
 58                     if (!flag)
 59                     {
 60                         return null;
 61                     }
 62                     exp = Expression.Equal(left, right);
 63                     return exp;
 64 
 65                 case EFilterOperator.NotEqual:
 66                     if (!flag)
 67                     {
 68                         return null;
 69                     }
 70                     exp = Expression.NotEqual(left, right);
 71 
 72                     return exp;
 73 
 74                 case EFilterOperator.GreaterThan:
 75                     if (!flag)
 76                     {
 77                         return null;
 78                     }
 79                     exp = Expression.GreaterThan(left, right);
 80 
 81                     return exp;
 82 
 83                 case EFilterOperator.LessThan:
 84                     if (!flag)
 85                     {
 86                         return null;
 87                     }
 88                     exp = Expression.LessThan(left, right);
 89 
 90                     return exp;
 91 
 92                 case EFilterOperator.GreaterThanOrEqual:
 93                     if (!flag)
 94                     {
 95                         return null;
 96                     }
 97                     exp = Expression.GreaterThanOrEqual(left, right);
 98 
 99                     return exp;
100 
101                 case EFilterOperator.LessThanOrEqual:
102                     if (!flag)
103                     {
104                         return null;
105                     }
106                     exp = Expression.LessThanOrEqual(left, right);
107 
108                     return exp;
109 
110                 case EFilterOperator.StartsWith:
111                     callExp = Expression.Call(left, typeof(string).GetMethod("StartsWith", new Type[] { typeof(string) }), new Expression[] { right });
112 
113                     return callExp;
114 
115                 case EFilterOperator.EndWith:
116                     callExp = Expression.Call(left, typeof(string).GetMethod("EndsWith", new Type[] { typeof(string) }), new Expression[] { right });
117                     return callExp;
118 
119                 case EFilterOperator.Contains:
120 
121                     callExp = Expression.Call(left, typeof(string).GetMethod("Contains", new Type[] { typeof(string) }), new Expression[] { right });
122 
123                     return callExp;
124 
125                 case EFilterOperator.NotContains:
126                     callExp = Expression.Call(left, typeof(string).GetMethod("Contains", new Type[] { typeof(string) }), new Expression[] { right });
127                     var not = Expression.Not(callExp);//取反
128 
129                     return not;
130             };
131 
132             return null;
133         }
134 
135         /// <summary>
136         /// 获取属性表达式
137         /// </summary>
138         /// <param name="expression"></param>
139         /// <param name="propertyName"></param>
140         public static MemberExpression GetPropertyExp(Expression expression, string propertyName)
141         {
142             string orginalName;
143 
144             switch (propertyName)
145             {
146                 case "标识":
147                     orginalName = "Guid";
148 
149                     break;
150 
151                 case "颜色":
152                     orginalName = "Color";
153                     break;
154 
155                 case "类型":
156                     orginalName = "Type";
157                     break;
158 
159                 case "图层":
160                     orginalName = "Layer";
161                     break;
162 
163                 case "名称":
164                     orginalName = "Name";
165                     break;
166 
167                 default:
168                     orginalName = propertyName;
169                     break;
170             }
171 
172             return Expression.Property(expression, orginalName);
173         }
174 
175         /// <summary>
176         /// 合并条件表达式
177         /// </summary>
178         /// <param name="left"></param>
179         /// <param name="right"></param>
180         /// <returns></returns>
181         public static BinaryExpression JionCondition(Expression left, Expression right)
182         {
183             return Expression.AndAlso(left, right);
184         }
185 
186         /// <summary>
187         /// 此处可省略
188         /// </summary>
189         /// <param name="propertyName"></param>
190         /// <param name="condition"></param>
191         /// <param name="content"></param>
192         /// <returns></returns>
193         [Obsolete("", true)]
194         private Func<UserDataProxy, bool> CreateLambda(string propertyName, EFilterOperator condition, string content)
195         {
196             string orginalName;
197 
198             switch (propertyName)
199             {
200                 case "标识":
201                     orginalName = "Guid";
202 
203                     break;
204 
205                 case "颜色":
206                     orginalName = "Color";
207                     break;
208 
209                 case "类型":
210                     orginalName = "Type";
211                     break;
212 
213                 case "图层":
214                     orginalName = "Layer";
215                     break;
216 
217                 case "名称":
218                     orginalName = "Name";
219                     break;
220 
221                 default:
222                     orginalName = propertyName;
223                     break;
224             }
225 
226             var paraExp = Expression.Parameter(typeof(UserDataProxy), "u");//原始类型
227 
228             var propertyExp = Expression.Property(paraExp, orginalName);//属性定义
229 
230             if (content == null)
231             {
232                 return null;
233             }
234             var flag = double.TryParse(content, out double num);//转换数字 能够转换是数字,不能就是文本
235 
236             Expression<Func<UserDataProxy, bool>> lambda = null;//最终结果
237             BinaryExpression exp;//二位运算符表达式
238 
239             Expression left;//左侧表达式
240             ConstantExpression right;//右侧表达式
241 
242             if (flag)
243             {
244                 left = Expression.Call(null, typeof(double).GetMethod("Parse", new Type[] { typeof(string) }), new Expression[] { propertyExp });
245 
246                 right = Expression.Constant(num, typeof(double));
247             }
248             else
249             {
250                 left = Expression.Call(propertyExp, typeof(string).GetMethod("ToString", new Type[] { }), new Expression[] { });//属性转换为字符串
251                 right = Expression.Constant(content, typeof(string));
252             }
253 
254             MethodCallExpression callExp;
255             switch (condition)
256             {
257                 case EFilterOperator.Equal:
258                     if (!flag)
259                     {
260                         return null;
261                     }
262                     exp = Expression.Equal(left, right);
263                     lambda = Expression.Lambda<Func<UserDataProxy, bool>>(exp, new ParameterExpression[] { paraExp });
264                     break;
265 
266                 case EFilterOperator.NotEqual:
267                     if (!flag)
268                     {
269                         return null;
270                     }
271                     exp = Expression.NotEqual(left, right);
272                     lambda = Expression.Lambda<Func<UserDataProxy, bool>>(exp, new ParameterExpression[] { paraExp });
273                     break;
274 
275                 case EFilterOperator.GreaterThan:
276                     if (!flag)
277                     {
278                         return null;
279                     }
280                     exp = Expression.GreaterThan(left, right);
281                     lambda = Expression.Lambda<Func<UserDataProxy, bool>>(exp, new ParameterExpression[] { paraExp });
282                     break;
283 
284                 case EFilterOperator.LessThan:
285                     if (!flag)
286                     {
287                         return null;
288                     }
289                     exp = Expression.LessThan(left, right);
290                     lambda = Expression.Lambda<Func<UserDataProxy, bool>>(exp, new ParameterExpression[] { paraExp });
291                     break;
292 
293                 case EFilterOperator.GreaterThanOrEqual:
294                     if (!flag)
295                     {
296                         return null;
297                     }
298                     exp = Expression.GreaterThanOrEqual(left, right);
299                     lambda = Expression.Lambda<Func<UserDataProxy, bool>>(exp, new ParameterExpression[] { paraExp });
300                     break;
301 
302                 case EFilterOperator.LessThanOrEqual:
303                     if (!flag)
304                     {
305                         return null;
306                     }
307                     exp = Expression.LessThanOrEqual(left, right);
308                     lambda = Expression.Lambda<Func<UserDataProxy, bool>>(exp, new ParameterExpression[] { paraExp });
309                     break;
310 
311                 case EFilterOperator.StartsWith:
312                     callExp = Expression.Call(left, typeof(string).GetMethod("StartsWith", new Type[] { typeof(string) }), new Expression[] { right });
313                     lambda = Expression.Lambda<Func<UserDataProxy, bool>>(callExp, new ParameterExpression[] { paraExp });
314                     break;
315 
316                 case EFilterOperator.EndWith:
317                     callExp = Expression.Call(left, typeof(string).GetMethod("EndsWith", new Type[] { typeof(string) }), new Expression[] { right });
318                     lambda = Expression.Lambda<Func<UserDataProxy, bool>>(callExp, new ParameterExpression[] { paraExp });
319                     break;
320 
321                 case EFilterOperator.Contains:
322 
323                     callExp = Expression.Call(left, typeof(string).GetMethod("Contains", new Type[] { typeof(string) }), new Expression[] { right });
324                     lambda = Expression.Lambda<Func<UserDataProxy, bool>>(callExp, new ParameterExpression[] { paraExp });
325                     break;
326 
327                 case EFilterOperator.NotContains:
328                     callExp = Expression.Call(left, typeof(string).GetMethod("Contains", new Type[] { typeof(string) }), new Expression[] { right });
329                     lambda = Expression.Lambda<Func<UserDataProxy, bool>>(Expression.Not(callExp), new ParameterExpression[] { paraExp });
330                     break;
331             };
332 
333             return lambda.Compile();
334         }
335     }

 运行测试

 1 internal class Program
 2     {
 3         public static Func<object, bool> Show()
 4         {
 5             return null;
 6         }
 7 
 8         private static void Main(string[] args)
 9         {
10             var list = new List<object>()
11             {
12                   new UserDataProxy(){Color="红色",Name="王义夫",Length="120"},
13                   new UserDataProxy(){Color="绿色",Name="王受人",Length="2120"},
14                   new UserDataProxy(){Color="蓝色",Name="王马子",Length="920"},
15                   new UserDataProxy(){Color="白色",Name="张三义",Length="1120"},
16                   new UserDataProxy(){Color="紫色",Name="里义夫",Length="1120"},
17                   new UserDataProxy(){Color="红色",Name="王义夫",Length="1020"},
18                   new UserDataProxy(){Color="红色",Name="王首任",Length="750"},
19                   new UserDataProxy(){Color="红色",Name="李义夫",Length="1210"},
20                   new UserDataProxy(){Color="红色",Name="勇义夫",Length="1110"},
21             };
22 
23             Console.WriteLine($"过滤之前\n");
24             list.ForEach(user =>
25             {
26                 var uu = user as UserDataProxy;
27 
28                 Console.WriteLine($"Color:{uu.Color},Length:{uu.Length},Name:{uu.Name}");
29             });
30 
31             var collection = CollectionViewSource.GetDefaultView(list);
32 
33             //第一个条件
34             var p1 = "Color";
35             var c1 = EFilterOperator.Contains;
36             var t1 = "";
37 
38             //第二个条件
39             var p2 = "Length";
40             var c2 = EFilterOperator.GreaterThan;
41             var t2 = "1000";
42 
43             //第三个条件
44             var p3 = "Name";
45             var c3 = EFilterOperator.NotContains;
46             var t3 = "";
47 
48             //生成条件1
49             var o = Expression.Parameter(typeof(object));
50 
51             var objExp = ExpressionTreeHelper.ConvertTo<UserDataProxy>(o);
52 
53             var m1 = ExpressionTreeHelper.GetPropertyExp(objExp, p1);
54 
55             var condition1 = ExpressionTreeHelper.CreateCondition(m1, c1, t1);
56 
57             //生成条件2
58             var m2 = ExpressionTreeHelper.GetPropertyExp(objExp, p2);
59 
60             var condition2 = ExpressionTreeHelper.CreateCondition(m2, c2, t2);
61 
62             //生成条件3
63             var m3 = ExpressionTreeHelper.GetPropertyExp(objExp, p3);
64 
65             var condition3 = ExpressionTreeHelper.CreateCondition(m3, c3, t3);
66 
67             //合并条件
68             var r1 = ExpressionTreeHelper.JionCondition(condition1, condition2);//第一次过滤
69 
70             //r1 = ExpressionTreeHelper.JionCondition(r1, condition3);//添加条件后过滤
71 
72             var s = Expression.Lambda<Predicate<object>>(r1, o);//创建Lambda表达式
73 
74             var func = s.Compile();//编译成委托
75 
76             if (func != null)
77             {
78                 //属性可能为null,在此处抛出异常
79                 try
80                 {
81                     collection.Filter = func;
82                     collection.Refresh();
83                 }
84                 catch (Exception ex)
85                 {
86                     Console.WriteLine($"{ex.Message}");
87                 }
88             }
89 
90             Console.WriteLine($"过滤之后\n");
91             foreach (var item in collection)
92             {
93                 var u = item as UserDataProxy;
94 
95                 Console.WriteLine($"Color:{u.Color},Length:{u.Length},Name:{u.Name}");
96             }
97         }
98     }

过滤结果

C# Expression创建ICollectionView的动态多重过滤条件

C# Expression创建ICollectionView的动态多重过滤条件

上一篇:wpf,对于列表模板里点击事件的2种写法的差异


下一篇:WPF 的 Window 样式控件模板如何实现关闭后弹窗提示