ListView is one of my favourite UI controls available in Xamarin.Forms. It is mostly easy to use and customise. Just bind a collection of data, define the representation of each item and you are done!
However, there is one pitfall which most of the developers tend to ignore - if the bound collection is empty, the ListView will have nothing to show. Depending on the targeting platform it may look ugly or confusing for the end user.
In this blogpost we will check few possible solutions. One solution will be purely implemented on the ViewModel level and the other one will be a reusable ListView control wrapper.
Let’s start with a simple case where you have a single ListView in the app and a reusable solution may sound like an overkill. In this case we will need to add an empty list indication to the View/Page and swap the IsVisible property between the ListView and the indicator when the collection become empty:
As you see both Label and ListView has the IsVisible property bound to IsNotEmptyData property that is defined on the ViewModel and look like this:
When Data property is changing it also raising a change event of the IsNotEmptyData property. Quite easy, but not reusable with multiple ListViews in the app.
Second approach I want to demonstrate is a custom control which simply wraps a ListView control by a Label and the visibility logic is managed by it. Here is how our XAML will look like using this approach:
The ListView is still under your full control as it is being defined right here. All you need is to set the EmptyMessage property and you should be ready to go! Lets take a look on the StaticListViewWithEmptyMessage control:
First we define a BindableProperty of type ListView that allows us to expose the ListView fully as demonstrated above. In order to show/hide our ListView we have to listen and response correctly to related changes.
Please note that both of the examples assumed that the collection bound to the ListView is a static collection if you want to handle a dynamic collection, you will have to use ObservableCollection and listen to CollectionChanged event instead.