How to implement SearchBox functionality in incrementally(Lazy) loaded ListView of UWP
Asked Answered
B

1

2

I have a ListView in UWP Application which binds 100 items on 1st load, then after loading is completed it binds another 100 i.e. it is incrementally loaded.

Here is a code :

<ListView x:Name="lstWords" ItemsSource="{Binding Items}" DataFetchSize="1" IncrementalLoadingTrigger="Edge" IncrementalLoadingThreshold="5" SelectionChanged="lstItems_SelectionChanged">
   <ListView.ItemTemplate>
     <DataTemplate>
       <StackPanel>
         <TextBlock Text="{Binding Name}"></TextBlock>
         <TextBlock Text="{Binding ID}" Visibility="Collapsed"></TextBlock>
       </StackPanel>
     </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

And the code which binds This ListView with incremental loading (Lazy loading) is as follows :

public class IncrementalLoadingCollection : ObservableCollection<Words>, ISupportIncrementalLoading
{
    uint x = 1;
    public bool HasMoreItems { get { return x < 10000; } }
    public IAsyncOperation<LoadMoreItemsResult> LoadMoreItemsAsync(uint count)
    {
        var page = new Index();
        string Id = localSettings.Values["Id"].ToString();
        return AsyncInfo.Run(async cancelToken =>
        {
            var apiData = await page.GetData(Id, x.ToString()); 
            foreach (var i in apiData)
            { 
                Add(new Words()
                {
                    Name = i.Name, ID=i.ID
                });
            }
            x += (uint)apiData.Count(); 
            return new LoadMoreItemsResult { Count = (uint)apiData.Count() };
        });
    }
}

public class ViewModelWords
{
    public ViewModelWords()
    {
        Items = new IncrementalLoadingCollection();
    } 
    public IncrementalLoadingCollection Items { get; set; }
}

The code for GetData() method mentioned here is in another class Index & is as follows :

public sealed partial class Index : Page
{
  List<Words> loadedList = new List<Words>();
  public class Words
  {
     public string ID { get; set; }
     public string Name { get; set; }
     public override string ToString() { return this.Name; }
  }


  public async Task<IEnumerable<Words>> GetData(string Id, string limit)
  {
     string mainUrlForWords = ApiUrl

      using (var httpClient = new HttpClient())
      {
         var dataUri = await httpClient.GetStringAsync(mainUrlForWords);
         JsonObject jsonObject = JsonObject.Parse(dataUri.ToString());
         JsonArray jsonArray = jsonObject["payload"].GetArray();
         foreach (JsonValue groupValue in jsonArray)
         {
            JsonObject groupObject = groupValue.GetObject();
            loadedList.Add(new Words { Name = groupObject.GetNamedString("name"), ID = groupObject.GetNamedString("id") });
         }
         return loadedList;
       }
   }
}

As mentioned in the question i want to implement searchBox functionality for above ListView i.e. the List is already loaded with items say 100 items, now in searchBox i will enter any word/text for the matches in items in the ListView, it should return only matched items based on word/text entered.

e.g. suppose listview items are as follows :

Abbasds, Abbsdf, ABCdef, Adehf

If i type 'ab' it must return following items : Abbasds, Abbsdf, ABCdef

If i type 'Abb' is must return : Abbasds, Abbsdf

I have tried implementing the said functionality using following code :

 <SearchBox x:Name="searchWords" QueryChanged="search_Words" PlaceholderText="Filter by..."></SearchBox>


private void search_Words(SearchBox sender, SearchBoxQueryChangedEventArgs e)
    {
        if (loadedList.Count>0)
        {
            lstWords.ItemsSource = loadedList.Where(a => a.ToString().ToUpper().Contains(searchWords.QueryText.ToUpper()));
        }
    }

But it fails to achieve the said functionality. When i debugged the code loadedList.count showed 0. while on App View ListView is loaded with items & can be seen on UI page.

Can anyone figure this out or provide some appropriate solution for the SearchBox functionality??

Brahe answered 22/8, 2018 at 7:17 Comment(7)
What is loadedList and where do you initialize this field in the view?Jankey
Why not use a CollectionView?Arredondo
@Arredondo can you please provide more guidance on CollectionView with coding example?Brahe
@Jankey loadedList is a list of type <Words> see the updated question & codeBrahe
Here is a link about CollectionView with code examples.Arredondo
@Arredondo the said link is for WPF, while my application is in UWP & UWP is slightly different than WPF, Also classes, functions, & methods are differentBrahe
@Arredondo moreover in that case incremental loading functionality won't work!Brahe
J
1

Your IncrementalLoadingCollection creates a new instance of an Index page which makes no sense at all.

I guess you simply want to get the items from the ListBox:

private void search_Words(SearchBox sender, SearchBoxQueryChangedEventArgs e)
{
    lstWords.ItemsSource = listBox.Items.OfType<Words>().Where(a => a.ToString().ToUpper().Contains(searchWords.QueryText.ToUpper())).ToArray();
}
Jankey answered 23/8, 2018 at 14:36 Comment(6)
Your solution looks quite good, but here are few complications : what is listBox in this case? also suppose if there are 100 items which are binded to the ListView & if i type 'ab' in searchBox it will return items starting with ab & that's fine, but if i removed 'b' from 'ab' by using backspace, then in that case your condition will fail. As in suppose from 100 items there are 30 items which matches querystring 'ab'.. next time if i remove 'b' from 'ab' then it will return items starting with 'a' from those 30 items only, not from the 100 items.Brahe
listBox is the ListBox in the view. I assume that the SearchBox and the ListBox belong to the same view.Jankey
then it will be like lstWords.ItemsSource = lstWords.Items.OfType<Words>()....... And in this case if i backspace any character from search query then the condition will fail. i.e. if searchQuery : ab returns 10 records, then after backspacing b from ab it will search string within those 10 items only & not in all items, i.e. 100 in this case!!!!Brahe
@Brahe So in this case, you should create query from those 10 items and select the compatible items as the ItemsSource to make them display in the result.Panjandrum
@BreezeLiu-MSFT yeah that thing is working, what i want is to search items in all 100 available items & not in 10 itemsBrahe
That should be similar to query the 10 items, you should query the corresponding items from all your resource but not the diplayed items resource from search ab. May be the data source has changed, you should make sure the resource is correct.Panjandrum

© 2022 - 2024 — McMap. All rights reserved.