This page describes how to customize filtered lists that additionally accept user inputs as filter criteria. The following examples are based on the Children.Items collection, however, Properties or Documents can be filtered too. (True?)
This implementation is different from Property-Based Filtering, that simply applies the inputs to the unfiltered child list. Property Based Content Filters |
Four elements are required for Custom Filtering:
- Input field - for user inputs.
- EvalExpression - for converting user inputs into a filter expression.
- Collection Filter - for applying the expression to a collection.
- Items control - for displaying the filtered items.
This system acts dynamically to output the filtered list, without requiring the use of an Evaluation button, and directly outputs all items that match the filter input.
This page will describe the basic implementation, but also how to extend the functionality:
- For multiple inputs.
- For filtering based on user input and object Meta data.
Basic Implementation
To build the filter in XAML, you will need to place an EvalExpression and a Collection Filter in the Resources of your container (most likely, a Grid), and the Input and List output in the container's content.
The following namespaces are be used:
UWP
xmlns:cv="using:UBIK.WinX.UI.CollectionView"
Xamarin
Resources
It is recommended to place the EvalExpression and Collection Filter into the <Grid.Resources>, as follows. For the Collection Filter, use ListCollectionView for UWP & Content filtering for Xamarin:
UWP
<controls:EvalExpression x:Name="FilterExpression" Context="{Binding}" Expression="(P1==null||P1=="") ? "true" : P0">
<controls:EvalExpressionParameter Name="P0"
Value="{Binding ElementName=InputTextboxName, Path=Text, Converter={StaticResource StringFormatConverter}, ConverterParameter='Item.Values["NAME"].ToLower().Contains("{0}".ToLower())==true'}" />
<controls:EvalExpressionParameter Name="P1"
Value="{Binding ElementName=InputTextboxName, Path=Text}" />
</controls:EvalExpression>
<cv:ListCollectionView
x:Key="FilterView"
Expression="{Binding ElementName=FilterExpression, Path=Result}"
ItemsSource="{Binding Children.Items}" />
</Grid.Resources>
Xamarin
<controls:EvalExpression x:Key="FilterExpression" Expression="(P1==null||P1=="") ? "true" : P0" Context="{Binding}">
<controls:EvalExpressionParameter Name="P0" Value="{Binding Path=Text, Source={x:Reference InputEntry}, Converter={StaticResource Formatter}, ConverterParameter='Item.Values["NAME"].ToLower().Contains("{0}".ToLower())==true'}" />
<controls:EvalExpressionParameter Name="P1" Value="{Binding Path=Text, Source={x:Reference InputEntry}}" />
</controls:EvalExpression>
<controls:SfDataSourceExt
x:Key="FilterView"
Expression="{Binding Path=Result, Source={StaticResource FilterExpression}}"
ItemsSource="{Binding Children.Items}" />
</Grid.Resources>
The EvalExpression Expression first checks whether the TextBox input is empty (as this would otherwise incorrectly be considered a filter input, whereby the property should be empty) and if so returns the unfiltered list (expression outcome hardcoded to 'true'), otherise, apply the filter (expression outcome is taken from string constructed in ConverterParameter of P0)
There are two important details of the EvalExpressionParameter to note here:
- The ElementName=InputTextboxName should match exactly to the name of your Input control.
- The Item.Values["NAME"] should be adapted to refer to the property that should be filtered by this input.
TextBox
The input field is just a basic Textbox/Entry we will use to input the filter criteria value. The only important detail for this input control is the name, which must be passed back to the EvalExpressionParameter.
It will look like this:
UWP
Xamarin
Items control
An items control will likely be used for displaying filtered results, such as controls:SelectionBoundListView for UWP & SfListViewExt for Xamarin:
UWP
x:Name="FilterQueryList"
ItemsSource="{StaticResource FilterView}" />
Xamarin
x:Name="FilterQueryResultList"
ItemsSource="{Binding DisplayItems, Source={StaticResource FilterView}}" />
Multiple User Inputs
It is likely that the customizing is required to work with multiple user inputs for the same filter. In this case, the EvalExpression must be adapted to combine the inputs (most likely using an AND relation, for a 'filtering-down' effect), as well as to deliver the full list when nothing is inputted. Of course, additional TextBox / input controls will be required for every added property.
UWP
<controls:EvalExpressionParameter Name="P0" Value="{Binding ElementName=NAME_InputTextbox, Path=Text, Converter={StaticResource StringFormatConverter}, ConverterParameter='Item.Values["NAME"].ToLower().Contains("{0}".ToLower())==true'}" />
<controls:EvalExpressionParameter Name="P1" Value="{Binding ElementName=NAME_InputTextbox, Path=Text}" />
<controls:EvalExpressionParameter Name="P00" Value="{Binding ElementName=DESCR_InputTextBox, Path=Text, Converter={StaticResource StringFormatConverter}, ConverterParameter='Item.Values["DESCR"].ToLower().Contains("{0}".ToLower())==true'}" />
<controls:EvalExpressionParameter Name="P11" Value="{Binding ElementName=DESCR_InputTextBox, Path=Text}" />
</controls:EvalExpression>
Xamarin
<controls:EvalExpressionParameter Name="P0" Value="{Binding Path=Text, Source={x:Reference NAME_InputEntry}, Converter={StaticResource StringFormatConverter}, ConverterParameter='Item.Values["NAME"].ToLower().Contains("{0}".ToLower())==true'}" />
<controls:EvalExpressionParameter Name="P1" Value="{Binding Path=Text, Source={x:Reference NAME_InputEntry}}" />
<controls:EvalExpressionParameter Name="P00" Value="{Binding Path=Text, Source={x:Reference DESCR_InputEntry}, Converter={StaticResource StringFormatConverter}, ConverterParameter='Item.Values["DESCR"].ToLower().Contains("{0}".ToLower())==true'}" />
<controls:EvalExpressionParameter Name="P11" Value="{Binding Path=Text, Source={x:Reference DESCR_InputEntry}" />
</controls:EvalExpression>
The above example shows how to combine inputs for two properties, NAME and DESCR. For each additional property you need to:
- Add the TextBox to the empty check in the first part of the EvalExpression Expression (P1, P11).
- Add the filter logic to the concatinated filter expression (P0, P00).
Due to the escaped syntax required in the Expression, +"&&"+ |
Once the additional input controls have been created and referenced as EvalExpressionParameters, and the EvalExpression has been adapted as shown, the filter should already function as required; the Collection Filter and Items Control do not need to be adapted.
Combining User Input and MetaData
A common use of the Collection Filter is to filter child lists based on certain MetaData, such as MetaUID, to present groups of specific object types. Therefore, it is likely that a customizer may need to add hardcoded filter criteria to the EvalExpression, that in addition combine with user input, if any is provided.
The following describes how to implement such a scenario in XAML, using the CategoryBasic Implementation as a starting point.
UWP
<controls:EvalExpressionParameter Name="PX" Value="Item.Content.MetaUID.ToString().ToLower()=="6f73cde9-ed38-4cbd-8ca1-4597cc2ae621"" />
<controls:EvalExpressionParameter Name="P0" Value="{Binding ElementName=NAME_InputTextBox, Path=Text, Converter={StaticResource StringFormatConverter}, ConverterParameter='Item.Values["NAME"].ToLower().Contains("{0}".ToLower())==true'}" />
<controls:EvalExpressionParameter Name="P1" Value="{Binding ElementName=DESCR_InputTextBox, Path=Text, Converter={StaticResource StringFormatConverter}, ConverterParameter='Item.Values["DESCR"].ToLower().Contains("{0}".ToLower())==true'}" />
</controls:EvalExpression>
Xamarin
<controls:EvalExpressionParameter Name="PX" Value="Item.Content.MetaUID.ToString().ToLower()=="6f73cde9-ed38-4cbd-8ca1-4597cc2ae621"" />
<controls:EvalExpressionParameter Name="P0" Value="{Binding Path=Text, Source={x:Reference NAME_InputEntry}, Converter={StaticResource StringFormatConverter}, ConverterParameter='Item.Values["NAME"].ToLower().Contains("{0}".ToLower())==true'}" />
<controls:EvalExpressionParameter Name="P1" Value="{Binding Path=Text, Source={x:Reference DESCR_InputEntry}, Converter={StaticResource StringFormatConverter}, ConverterParameter='Item.Values["DESCR"].ToLower().Contains("{0}".ToLower())==true'}" />
</controls:EvalExpression>