Here's the scenario:
Silverlight 4.0, DataGrid, PagedCollectionView itemssource.
The objective is to apply a Filter to the PCV. The filter needs to be a Predicate<object>(Method) - where Method implements some logic against the object and returns true/false for inclusion.
What I have is a need to optionally include 3 different criteria in the filter logic and explicit code quickly gets ugly. We don't want that, do we?
So I see that there is a way to build an expression tree using PredicateBuilder and pass that into Linq.Where, a la:
With 3 optional criteria, I want to write something like:
Ratings.Filter = BuildFilterPredicate(); // Ratings = the PagedCollectionView
private Predicate<object> BuildFilterPredicate()
{
bool FilterOnOrder = !String.IsNullOrEmpty(sOrderNumberFilter);
var predicate = PredicateBuilder.False<object>();
if (ViewMineOnly)
{
predicate = predicate.And(Rating r => sUserNameFilter == r.Assigned_To);
}
if (ViewStarOnly)
{
predicate = predicate.And(Rating r => r.Star.HasValue && r.Star.Value > 0);
}
if (FilterOnOrder)
{
predicate = predicate.And(Rating r => r.ShipmentInvoice.StartsWith(sOrderNumberFilter));
}
return predicate;
}
Of course this won't compile because PredicateBuilder creates an Expression<Func<T, bool>> not an actual predicate method. But I see that there are ways to convert an expression tree into a method so it seemed to me there ought to be a way to accomplish what I'm after without resorting to a bunch of nested if/then/else statements.
So the question is - is there a way to build a predicate method dynamically?
// The expression tree to execute.
BinaryExpression be = Expression.Power(Expression.Constant(2D), Expression.Constant(3D));
// Create a lambda expression.
Expression<Func<double>> le = Expression.Lambda<Func<double>>(be);
// Compile the lambda expression.
Func<double> compiledExpression = le.Compile();
// Execute the lambda expression.
double result = compiledExpression();
// Display the result.
Console.WriteLine(result);
// This code produces the following output:
// 8
I faced the same problem. I had 3 criteria.
What I did is the following :
One method to validate each criteria
One method to validate the object
The code looked quite clean and it was easy to maintain.
Ratings.Filter = new predicate<objects>(validateObject);
private bool validateObject(object o)
{
return validateFirstCriteria(o) &&
validateSecondCriteria(o) &&
validateThirdCriteria(o);
}
private bool validateFirstObject(object o)
{
if (ViewMineOnly)
{
Rating r = o as Rating;
if (o != null)
{
return (r.Star.HasValue && r.Star.Value > 0);
}
}
return false;
}
private bool validateSecondObject(object o)
{
if (ViewStarOnly)
{
Rating r = o as Rating;
if (o != null)
{
return sUserNameFilter == r.Assigned_To;
}
}
return false;
}
private bool validateThirdObject(object o)
{
if (FilterOnOrder)
{
Rating r = o as Rating;
if (o != null)
{
return r.ShipmentInvoice.StartsWith(sOrderNumberFilter);
}
}
return false;
}
You can convert the expression tree to a lambda expression and then compile the lambda expression. After then you can use it as a method. Exemple :
// The expression tree to execute.
BinaryExpression be = Expression.Power(Expression.Constant(2D), Expression.Constant(3D));
// Create a lambda expression.
Expression<Func<double>> le = Expression.Lambda<Func<double>>(be);
// Compile the lambda expression.
Func<double> compiledExpression = le.Compile();
// Execute the lambda expression.
double result = compiledExpression();
// Display the result.
Console.WriteLine(result);
// This code produces the following output:
// 8
发布评论
评论(3)
要对 PagedCollectionView 执行此操作,您需要有一个谓词。所以它看起来像:
并构建表达式:
然后设置过滤器:
to do this for a PagedCollectionView, you need to have a Predicate. So it looks like:
and build the expression:
and then set the filter:
我遇到了同样的问题。我有 3 个标准。
我所做的如下:
代码看起来非常干净并且易于维护。
编辑
如果您想坚持使用表达式树。您可以在这里查看: http://msdn.microsoft.com/en -us/library/bb882536.aspx
您可以将表达式树转换为 lambda 表达式,然后编译 lambda 表达式。之后你就可以使用它作为一种方法。示例:
I faced the same problem. I had 3 criteria.
What I did is the following :
The code looked quite clean and it was easy to maintain.
EDIT
If you want to stuck to Expression trees. You could take a look here : http://msdn.microsoft.com/en-us/library/bb882536.aspx
You can convert the expression tree to a lambda expression and then compile the lambda expression. After then you can use it as a method. Exemple :
感谢本杰明的提示和这篇文章 -> 如何转换 Func谓词?
我想通了。
本质是:
这会将表达式树编译为单个函数,并返回一个谓词来调用该函数。
在使用中,它看起来像:
谢谢!
Thanks to Benjamin's hints and this post -> How to convert Func<T, bool> to Predicate<T>?
I figured it out.
The essence is:
This will compile the expression tree to a single function and return a predicate to call the function.
In use, it looks like:
Thanks!