Question

I am trying to develop a page in a WP8 app which has a search box at the top and a list of items that match the search below, updating as the search box updates. Pretty straightforward, right? Except I can't get it to work.

After perusing StackOverflow and the interwebz, the recommended solution seems to be to use CollectionViewSource. Well, I'm trying to use it and no items show up. As soon as I switch to the ObservableCollection containing my items in XAML, everything shows up fine.

My data is loaded asynchronously from a DB.

XAML

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto" />
        <RowDefinition Height="*" />
    </Grid.RowDefinitions>

    <toolkit:PhoneTextBox Grid.Row="0" Hint="search query" ActionIcon="/Assets/Search.png" Text="{Binding SearchQuery, Mode=TwoWay}">
        <i:Interaction.Behaviors>
            <themes:TextBoxUpdateOnTextChangedBehavior />
        </i:Interaction.Behaviors>
    </toolkit:PhoneTextBox>
    <phone:LongListSelector Grid.Row="1" ItemsSource="{Binding SearchResults}" />
    <!-- I have also tried binding to SearchResults.View with no success -->
</Grid>

View Model

public class MyViewModel
{
    private ObservableCollection<MyItemViewModel> _allItems = new ObservableCollection<MyItemViewModel>();

    public CollectionViewSource SearchResults { get; private set; }

    public MyViewModel()
    {
        SearchResults = new CollectionViewSource { Source = _allItems };
        _allItems.CollectionChanged += (_, __) => SearchResults.View.Refresh();

        LoadAllItemsAsync();
    }

    private async void LoadAllItemsAsync()
    {
        IList<MyItemModel> models = await LoadMyModels();
        _allItems.AddRange(models.Select(model => new MyItemViewModel(model)));
    }
}

As you can see, I haven't even attempted to write filtering code yet. Shouldn't the code above basically show a LongListSelector with all the items I have loaded? If I change the SearchResults type to ObservableCollection<MyItemViewModel> and have the getter return _allItems, my page shows the expected items. What am I doing wrong here?

Was it helpful?

Solution

The problem is that the LongListSelector control requires that its ItemsSource implements IList, which CollectionViewSource doesn't do. This means you can't bind a CollectionViewSource to a LongListSelector out of the box. You can see this by trying to set it in the code-behind file like this:

myLongListSelector.ItemsSource = myCollectionViewSource.View;

Which gives an error saying it can't convert the view to an IList.

I know atleast two solutions to this, one is to write a wrapper class around CollectionViewSource which does implement IList and then bind to that. Another question gives an example of this (I haven't tried it thought): LongListSelector grouping using CollectionView in Windows Phone 7 or Windows Phone 8

Another method is to not use CollectionViewSource and instead using System.Linq for sorting like suggested in this question: How to Sort a LongListSelector in Windows Phone

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top