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?)
{{Attention|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.
<br>
<br>
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.
<br>
== 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:
<tabs>
<tab name="UWP">
<source lang = "xml">
xmlns:controls="using:UBIK.WinX.Controls"
xmlns:cv="using:UBIK.WinX.UI.CollectionView"
</source>
</tab>
<tab name="Xamarin">
<source lang = "xml">
xmlns:controls="clr-namespace:UBIK.CPL.Controls;assembly=UBIK.CPL"
</source>
</tab>
</tabs>
=== Resources ===
It is recommended to place the EvalExpression and Collection Filter into the <Grid.Resources>, as follows.
For the Collection Filter, use [[XAML_Changes_in_UBIK_WinX_3.5#Filtering_by_expressions|ListCollectionView]] for UWP & [[Xamarin_XAML#Feature related|Content filtering]] for Xamarin:
<tabs>
<tab name="UWP">
<source lang = "xml">
<Grid.Resources>
<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>
</source>
{{Attention|Note that the EvalExpression uses x:Name, which requires the 'ElementName' syntax seen in the cv:ListCollectionView.}}
</tab>
<tab name="Xamarin">
<source lang = "xml">
<Grid.Resources>
<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>
</source>
</tab>
</tabs>
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.
<br>
=== 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.
<br>
<br>
It will look like this:
<tabs>
<tab name="UWP">
<source lang = "xml">
<TextBox x:Name="InputTextboxName" />
</source>
</tab>
<tab name="Xamarin">
<source lang = "xml">
<Entry x:Name="InputEntry"/>
</source>
</tab>
</tabs>
=== Items control ===
An items control will likely be used for displaying filtered results, such as controls:SelectionBoundListView for UWP & [[Xamarin_XAML#SfListViewExt|SfListViewExt]] for Xamarin:
<tabs>
<tab name="UWP">
<source lang = "xml">
<controls:SelectionBoundListView
x:Name="FilterQueryList"
ItemsSource="{StaticResource FilterView}" />
</source>
</tab>
<tab name="Xamarin">
<source lang="xml">
<controls:SfListViewExt
x:Name="FilterQueryResultList"
ItemsSource="{Binding DisplayItems, Source={StaticResource FilterView}}" />
</source>
</tab>
</tabs>
<br>
== 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.
<tabs>
<tab name="UWP">
<source lang = "xml">
<controls:EvalExpression x:Name="Multiple_FilterExpression" Expression="(P1=="" && P11=="") ? "true" : P0 +"&&"+ P00" Context="{Binding}">
<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>
</source>
</tab>
<tab name="Xamarin">
<source lang = "xml">
<controls:EvalExpression x:Name="Multiple_FilterExpression" Expression="(P1=="" && P11=="") ? "true" : P0 +"&&"+ P00" Context="{Binding}">
<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>
</source>
</tab>
</tabs>
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).
{{Attention|Due to the escaped syntax required in the Expression, <source lang = "xml">+"&&"+</source> is the correct syntax required to concatinate filter expressions together.}}
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.
<br>
== 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.
<tabs>
<tab name="UWP">
<source lang = "xml">
<controls:EvalExpression x:Name="MetaUID_FilterExpression" Expression="PX +"&&"+ P0 +"&&"+ P1" Context="{Binding}">
<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>
</source>
</tab>
<tab name="Xamarin">
<source lang = "xml">
<controls:EvalExpression x:Name="MetaUID_FilterExpression" Expression="PX +"&&"+ P0 +"&&"+ P1" Context="{Binding}">
<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>
</source>
</tab>
</tabs>
The benefit of this Expression is that there will always be a positive result (as long as objects of the correct MetaUID exist in the collection), therefore it is not necessary to first check if all inputs are null and return 'true', as is the case in the [[:Category:Multiple_User_Inputs]] example. In this case, additonal inputs simply need to be added as EvalExpressionParameters and combined in the Expression using <source lang = "xml">+"&&"+</source>
== See also ==
* [[XAML]]
* [[XAML_Tips]]
* [[Xamarin_XAML]]
[[Category:Draft Roadmap|Draft Roadmap]]