Xamarin.Forms Projects
上QQ阅读APP看书,第一时间看更新

Creating the filter toggle function using a command

We want to be able to toggle between viewing only active items and all items. We will create a simple mechanism to do this.

Hook up the changes in the MainViewModel as follows:

  1. Open ViewModels/MainViewModel.cs and locate the ItemStatusChangeMethod.
  2. Add the implementation to the ItemStatusChanged method and a property called ShowAll to control the filtering:
private void ItemStatusChanged(object sender, EventArgs e)
{
if (sender is TodoItemViewModel item)
{
if (!ShowAll && item.Item.Completed)
{
Items.Remove(item);
}

Task.Run(async () => await
repository.UpdateItem(item.Item));

}
}


public bool ShowAll { get; set; }

The ItemStatusChanged event handler is triggered when we use the context action from the last section. Since the sender is always an object, we try to cast it to a TodoItemViewModel. If this is successful, we check whether we can remove it from the list if ShowAll is not true. This is a small optimization; we could have called LoadData and reloaded the entire list, but since the Items list is an ObservableCollection, it communicates to the ListView that one item has been removed from the list. We also call the repository to update the item to persist the change of status. 

The ShowAll property is what controls which state our filter is in. We need to adjust the LoadData method to reflect this:

  1. Locate the Load method in the MainViewModel.
  2. Add the lines of code marked in bold:
private async Task LoadData()
{
var items = await repository.GetItems();

if (!ShowAll)
{

items = items.Where(x => x.Completed == false).ToList();
}


var itemViewModels = items.Select(i =>
CreateTodoItemViewModel(i));
Items = new ObservableCollection<TodoItemViewModel>
(itemViewModels);
}

If ShowAll is false, we limit the content of the list to the items that have not been completed. We could do this either by having two methods, GetAllItems() and GetActiveItems(), or by using a filter argument that could be passed to GetItems(). Take a minute to think about how we would have implemented this.

Let's add the code that toggles the filter:

  1. Open ViewModels/MainViewModel.cs.
  2. Add the FilterText and ToggleFilter properties:
public string FilterText => ShowAll ? "All" : "Active";

public ICommand ToggleFilter => new Command(async () =>
{
ShowAll = !ShowAll;
await LoadData();
});

The FilterText property is a read-only property used to display the status as a string in human-readable form. We could have used a ValueConverter for this, but to save some time, we simply expose it as a property. The logic for the ToggleFilter command is a simple inversion of the state and then a call to LoadData. This, in turn, causes a reload of the list.

Before we can filter the items, we need to hook up the filter button:

  1. Open Views/MainView.xaml.
  2. Locate the Button that controls the filter (the only button in the file).
  3. Adjust the code to reflect the following code:
<Button Text="{Binding FilterText, StringFormat='Filter: {0}'}"
Command="{Binding ToggleFilter}" />

The app is now complete with regard to this feature! But it isn't very attractive; we'll deal with this in the following section.