我试图将过滤器应用于WPF中的DataGrid,过滤器属性需要谓词
例如:
dataGrid1.Filter = p => p.A_Field_Table1.Contains(textBox.Text);
但我的数据网格充满了反射,所以我只知道运行时数据网格内的对象类型。
然后我创建了一个动态生成Predicate< T> :
public static Predicate< T > GetPredicate< T >(string column, string valueP, T objSource, string table)
{
Type itemType = typeof(T);
ParameterExpression predParam = Expression.Parameter(itemType, "p");
Expression left = Expression.Property(predParam, itemType.GetProperty("A_" + column+ "_" + table));
var valueStr= Expression.Constant(valueP);
var typeOfStr = valueStr.Type;
var containsMethod = typeOfStr.GetMethod("Contains", new [] { typeof(string) });
var call = Expression.Call(left, containsMethod, valueStr);
Func< T, bool > function = (Func< T, bool >)Expression.Lambda(call, new[] { predParam }).Compile();
return new Predicate< T >(function);
}
然后在界面上调用此函数:
var dataGridItem = dataGrid.Items[0];
dataGrid1.Filter = Class_X.GetPredicate(columnRefName,textBox.Text,dataGridItem,tableRefName);
但泛型方法抛出一个异常,即类型T是&#34; object&#34;的类型,即使objSource是Model.TableName的类型。
我读了一些教程,说T在运行时无法解析,那么我应该使用&#34; dynamic&#34;而不是泛型类型。
我已经尝试过使用&#34;动态&#34;类型,但我将Lambda表达式转换为Func&lt;时得到异常动态,布尔&gt;。说我无法从&lt;转换Model.TableName,bool&gt;到&lt; System.Object,bool&gt;。
是否有更简单的方法来过滤由反射填充的数据网格?
答案 0 :(得分:1)
在这种情况下,您无法使用泛型。 Filter
是Func<object, bool>
,所以:
public static Predicate<object> GetPredicate(string column, string valueP, object objSource, string table)
{
Type itemType = objSource.GetType();
ParameterExpression predParam = Expression.Parameter(typeof(object), "p");
Expression left = Expression.Property(Expression.Convert(predParam, itemType), "A_" + column+ "_" + table);
var valueStr= Expression.Constant(valueP);
var typeOfStr = valueStr.Type;
var containsMethod = typeOfStr.GetMethod("Contains", new [] { typeof(string) });
var call = Expression.Call(left, containsMethod, valueStr);
//To handle null values. It considers null == string.Empty
//var left2 = Expression.Coalesce(left, Expression.Constant(string.Empty));
//var call = Expression.Call(left2, containsMethod, valueStr);
//If you want null values to be distinct from string.Empty, it's
//much more complex. You'll need a temporary variable (left2)
//where to put the value of the property, and then you can use the
//Expression.Condition (that is the ? : ternary operator) to
//test for null values
//var left2 = Expression.Variable(typeof(string));
//var assign = Expression.Assign(left2, left);
//var notNull = Expression.NotEqual(left2, Expression.Constant(null));
//var call = Expression.Call(left2, containsMethod, valueStr);
//var condition = Expression.Condition(notNull, call, Expression.Constant(false));
//var block = Expression.Block(new[] { left2 }, new Expression[] { assign, condition });
Predicate<object> function = Expression.Lambda<Predicate<object>>(call, new[] { predParam }).Compile();
return function;
}
“技巧”是在返回的函数中,参数被转换为“右”类型(由objSource.GetType()
获得)
请注意,如果您尝试在null
属性上使用NullReferenceException
,则不会测试行属性中的Contains
值null
< / p>