This is the UI of my application. It is a WPF based application that analyzes between devices (Something very similar to Wireshark).
The class that is being binded to the DataGrid is the following (Everything except Error and FuncType is bound to the grid:)
public class CommDGDataSource
{
public int Number { get; set; }
public string Time { get; set; }
public string Protocol { get; set; }
public string Source { get; set; }
public string Destination { get; set; }
public string Data { get; set; }
public bool Error { get; set; }
public FunctionType FuncType { get; set; }
}
Basically, I’m trying to design something where users can enter certain filter commands and only the rows that matches the condition should be displayed. Here are some examples (without the quote),
-
Entering “Error” should only display the datarows whose Error property has been set to true
-
Entering “source==someipaddress” should only display the matching IP address
-
Entering “number>100” should only display rows with number greater than 100
-
Multiple conditions should apply if separated by comma. (Error,source==someipaddress)
I’ve already created ICollectionView for my binding data to handle the filtering but I’m not sure about the approach I should take to parse the commands and properly handle the filtering to meet the above requirements.
Any guidance would be appreciated.
The 10,000 feet overview
Filtering data in a
DataGridis done by attaching a handler to theCollectionViewSource.Filterevent, so the actual problem is how to create aFilterEventHandlerfrom user input. This problem can be solved in a powerful manner with expression trees.I ‘m not going to go into detail with regards to how to parse the input string because that can range from very simple to very complicated; a powerful approach would be to use a tool like ANTRL to parse the input into an abstract syntax tree.
What I will show is how you can create a filter given that the input is parsed and the user’s intent is known (it is also quite easy to create the filter on the fly while parsing).
Let’s assume that the user entered “Number > 10” for the filter. If this filter were hardcoded, the
FilterEventHandlerwould look like this:Constructing a filtering event handler dynamically
What we ‘re going to do here is dynamically construct this method on the fly using expression trees. Let’s begin with some preamble:
We ‘re going to be constructing a
LambdaExpressionwhich has two parameters and a body. Let’s construct the parameters first:The body is going to be a
BlockExpression(this is not strictly necessary, but could come in handy later on). ABlockExpressionuses a number of variables and is comprised of any number of other expressions; very importantly, the last of these will be the block’s return value.The first line of the mock event handler given above tells us that we need one variable:
And we definitely need a predicate that produces the return value:
We are now ready to produce the body of the
BlockExpression. The body will need to access theItemproperty of the second parameter of the event handler (parameters[1]) and cast it tosourceTypebecauseFilterEventArgs.Itemis of typeobject, so we can’t use it directly. The result of the cast should be stored invariableand thenpredicatewill perform the test:Since
predicateis the last expression of the body it will also produce its return value.We can now construct the block expression and then finally the filtering lambda expression itself:
Plugging in the filter
One of the reasons we went to all this trouble is that now the compiler can construct a “real” method from the
filterexpression for us automatically! We can then simply plug it into theCollectionViewSource.Filterevent and enjoy filtering:Constructing complicated filters
The other reason to go with this approach is that it’s quite easy to extend the filtering logic. For example it’s easy to imagine that instead of hardwiring the predicate like this:
We could construct it from user input like this: