Reputation: 1018
I'm using IMobileServiceTable in an data access layer class and bind it to an listview. Initial loading works fine but filtering doesn't. It always returns the initial loaded data.
public class ItemsManager {
IMobileServiceTable<Item> itemTable;
public ItemsManager (IMobileServiceTable<Item> todoTable)
{
this.itemTable = todoTable;
}
public async Task<List<Item>> GetTasksAsync (string searchString)
{
//following doesn't work
var list = new List<Item> (await itemTable.Where(x => x.ItemID.Contains(searchString)).ToListAsync());
return list;
}
public async Task<List<Item>> GetTasksAsync ()
{
return new List<Item> (await itemTable.OrderBy(a =>a.ItemID).ToListAsync());
}
}
If it matter, following is my page code :
public partial class ItemsListXaml : ContentPage
{
IMobileServiceTable<Item> itemTable;
ItemsManager itemManager;
public ItemsListXaml ()
{
InitializeComponent ();
itemTable = App.client.GetTable<Item>();
itemManager = new ItemsManager(itemTable);
App.SetItemsManager (itemManager);
}
protected async override void OnAppearing ()
{
base.OnAppearing ();
listView.ItemsSource = await itemManager.GetTasksAsync ();
}
async void OnValueChanged (object sender, TextChangedEventArgs e) {
var t = e.NewTextValue;
// perform search on min 3 keypress
if (t.Length>3) {
listView.ItemsSource = await itemManager.GetTasksAsync(SearchFor.Text);
}
}
}
Upvotes: 0
Views: 380
Reputation: 49
It looks like the problem line is this:
var list = new List (await
itemTable.Where(x => x.ItemID.Contains searchString)).ToListAsync());
Not sure exactly what's going on there, but I did manage to get something similar working. The sample I have uses a proxy object to save on Azure fetches. I fetch once to get the initial list of tasks and save that to a local ObservableCollection object that I can bind to the list. Then, I can filter the collection object that is bound to the list (sample here).
You might have legitimate reasons for fetching a filtered list from Azure. In my mind - and bear with me because I'm no expert on app design - unless there is a significant period of time between the initial fetch of the list and the filter action where there might be new data introduced to the table, seems like just filtering a local object would perform better and be cheaper. The app could always handle push notifications to update the list as needed.
Basically, pull objects from Azure into it as shown here:
public async Task<ObservableCollection<ToDoItem>> GetTasksAsync()
{
try
{
return new ObservableCollection<ToDoItem>(await _todoTable.ReadAsync());
}
catch (MobileServiceInvalidOperationException msioe)
{
Debug.WriteLine(@"INVALID {0}", msioe.Message);
}
catch (Exception e)
{
Debug.WriteLine(@"ERROR {0}", e.Message);
}
return null;
}
Then, bind to list as shown here:
protected async override void OnAppearing()
{
base.OnAppearing();
App.TodoManager.TodoViewModel.TodoItems = await App.TodoManager.GetTasksAsync();
listViewTasks.ItemsSource = App.TodoManager.TodoViewModel.TodoItems;
}
In this example, “App.TodoManager.TodoViewModel.TodoItems” is the fully qualified path to the proxy object which is the ObservableCollection.
Then you can filter the proxy object and rebind it to the list. I haven’t actually implemented that part in the sample, but I did take down a copy of it and then added the code and seems to work fine. This would be the code:
Getting the filtered list:
public ObservableCollection<ToDoItem> GetFilteredList(string searchString)
{
return new ObservableCollection<ToDoItem>
(TodoViewModel.TodoItems.Where(x => x.Name.Contains(searchString)));
}
Calling helper method and binding to listview (Incorporating this into one of your example blocks):
async void OnValueChanged (object sender, TextChangedEventArgs e) {
var t = e.NewTextValue;
// perform search on min 3 keypress
if (t.Length>3) {
App.TodoManager.TodoViewModel.TodoItems = App.TodoManager.GetFilteredList(searchFor.Text);
listViewTasks.ItemsSource = App.TodoManager.TodoViewModel.TodoItems;
}
}
Upvotes: 1