Searchable ListView for Windows Universal Apps

Needed a quick implementation of a searchable ListView for Windows Universal apps, specifically Windows Phone 8.1 and came up with the following:


public class ListPicker : ListView
 {
 private IList _items = null;
 private PropertyInfo _filteringProperty = null;
 readonly BasicObservableCollection<object> _filteredList = new BasicObservableCollection<object>();
 
 public static readonly DependencyProperty FilterTextProperty = DependencyProperty.Register(
 "FilterText",
 typeof(String),
 typeof(ListPicker),
 new PropertyMetadata(null, (o, args) =>
 {
 ((ListPicker)o).OnFilterTextChanged((string)args.NewValue);
 }));

private void OnFilterTextChanged(string filter)
 {
 if (_items == null)
 {
 _items = (IList)ItemsSource;

if (_items != null && !string.IsNullOrWhiteSpace(DisplayMemberPath))
 {
 _filteringProperty = _items[0].GetType().GetProperties().First(p => p.Name == DisplayMemberPath);
 }

ItemsSource = _filteredList;
 }

_filteredList.Clear();


 if (string.IsNullOrEmpty(filter))
 {
 _filteredList.ReplaceAll(_items.Cast<object>());
 return;
 }

var filteredItems = _items.Cast<object>().Where(i =>
 {
 var value = i.ToString();
 if (_filteringProperty != null)
 {
 value = _filteringProperty.GetValue(i) as string;
 }

return value != null && value.Contains(filter);
 });

_filteredList.ReplaceAll(filteredItems);
 }
 }

With the following complimenting style:


 <Style TargetType="controls:ListPicker">
 <Setter Property="IsTabStop" Value="False"/>
 <Setter Property="TabNavigation" Value="Once"/>
 <Setter Property="IsSwipeEnabled" Value="True"/>
 <Setter Property="HorizontalContentAlignment" Value="Stretch"/>
 <Setter Property="VerticalContentAlignment" Value="Top"/>
 <Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Disabled"/>
 <Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto"/>
 <Setter Property="ScrollViewer.HorizontalScrollMode" Value="Disabled"/>
 <Setter Property="ScrollViewer.VerticalScrollMode" Value="Auto"/>
 <Setter Property="ScrollViewer.ZoomMode" Value="Disabled"/>
 <Setter Property="ScrollViewer.IsDeferredScrollingEnabled" Value="False"/>
 <Setter Property="ScrollViewer.BringIntoViewOnFocusChange" Value="True"/>
 <Setter Property="ItemContainerTransitions">
 <Setter.Value>
 <TransitionCollection>
 <AddDeleteThemeTransition/>
 <ReorderThemeTransition/>
 </TransitionCollection>
 </Setter.Value>
 </Setter>
 <Setter Property="ItemsPanel">
 <Setter.Value>
 <ItemsPanelTemplate>
 <ItemsStackPanel Orientation="Vertical"/>
 </ItemsPanelTemplate>
 </Setter.Value>
 </Setter>
 <Setter Property="Template">
 <Setter.Value>
 <ControlTemplate TargetType="ListView">
 <Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}">
 <Grid>
 <Grid.RowDefinitions>
 <RowDefinition Height="Auto"/>
 <RowDefinition Height="*"/>
 </Grid.RowDefinitions>
 <TextBox
 Margin="0,0,19,0"
 PlaceholderText="search"
 x:Name="FilterTextBox"
 Text="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=FilterText, 
 UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"/>
 <ScrollViewer
 Grid.Row="1"
 x:Name="ScrollViewer" AutomationProperties.AccessibilityView="Raw" BringIntoViewOnFocusChange="{TemplateBinding ScrollViewer.BringIntoViewOnFocusChange}" HorizontalScrollMode="{TemplateBinding ScrollViewer.HorizontalScrollMode}" HorizontalScrollBarVisibility="{TemplateBinding ScrollViewer.HorizontalScrollBarVisibility}" IsHorizontalRailEnabled="{TemplateBinding ScrollViewer.IsHorizontalRailEnabled}" IsHorizontalScrollChainingEnabled="{TemplateBinding ScrollViewer.IsHorizontalScrollChainingEnabled}" IsVerticalScrollChainingEnabled="{TemplateBinding ScrollViewer.IsVerticalScrollChainingEnabled}" IsVerticalRailEnabled="{TemplateBinding ScrollViewer.IsVerticalRailEnabled}" IsDeferredScrollingEnabled="{TemplateBinding ScrollViewer.IsDeferredScrollingEnabled}" TabNavigation="{TemplateBinding TabNavigation}" VerticalScrollBarVisibility="{TemplateBinding ScrollViewer.VerticalScrollBarVisibility}" VerticalScrollMode="{TemplateBinding ScrollViewer.VerticalScrollMode}" ZoomMode="{TemplateBinding ScrollViewer.ZoomMode}">
 <ItemsPresenter FooterTransitions="{TemplateBinding FooterTransitions}" FooterTemplate="{TemplateBinding FooterTemplate}" Footer="{TemplateBinding Footer}" HeaderTemplate="{TemplateBinding HeaderTemplate}" Header="{TemplateBinding Header}" HeaderTransitions="{TemplateBinding HeaderTransitions}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Padding="{TemplateBinding Padding}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
 </ScrollViewer>
 </Grid>
 </Border>
 </ControlTemplate>
 </Setter.Value>
 </Setter>
 </Style>

Only caveat is  this style needs to be added to the resources collection of your main application.  Also, BasicObservableCollection is simply an enhanced version of ObservableCollection that allows for items to be added to the collection in bulk before raising the collection changed event on the UI t thread, courtesy of Cory Charlton.

If anyone knows how I can embed the style into code, so it is all self contained, please advise.

Happy Coding.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s