New to Telerik UI for Xamarin? Download free 30-day trial

Load On Demand

Loading a large data set on a mobile device has its challenges. One of the most popular approaches is using incremental data loading as the items needs to be visualized. RadListView is capable of doing this using its load on demand functionality.

Configuration

The following properties are related to the LoadOnDemand feature:

  • IsLoadOnDemandEnabled(bool) - used to enable the load on demand mechanism of RadListView;
  • IsLoadOnDemandActive (bool) - this flag should be used when the data is retrieved asynchronously. It should be set to "True" when an async operation is started, to notify the ListView to show loading indicator and to "False" when items are loaded.

RadListView offers two loading modes through its LoadOnDemandMode property:

  • Automatic - the data is requested automatically when you scroll near the end of the listview.
  • Manual - a button is rendered at the end of the listview. The data is requested explicitly by pressing the button.

There are three ways to load the data on demand, regardless of the loading mode you've chosen:

  • Create a ListViewLoadOnDemandCollection instance as source and pass it to the ListView ItemsSource property.
  • Subscribe to LoadOnDemand event and add the loaded data to the source.
  • Use the LoadOnDemand UserCommand and add the loaded data to the source.

Either of the three approaches for loading items on demand in ListView works with both Automatic and Manual LoadOnDemandMode.

Using LoadOnDemandCollection

One possible approach to load items on demand is by utilizing the ListViewLoadOnDemandCollection which should be set as ItemsSource of the ListView. The ListViewLoadOnDemandCollection accepts an action in the constructor and this action is later executed by the ListView in a non-UI thread when new items are requested.

ListViewLoadOnDemandCollection can work both in Manual and Automatic mode. Below you can find an example with loading on demand through LoadOnDemandCollection.

First, let's define a sample ViewModel class with Source property of type ListViewLoadOnDemandCollection:

public class ListViewModel
{
    public ListViewLoadOnDemandCollection Source { get; set; }
    private int lodTriggerCount;
    public ListViewModel()
    {
        this.Source = new ListViewLoadOnDemandCollection((cancelationToken) =>
        {
            List<string> result = new List<string>();

            try
            {
                //simulates connection latency
                Task.Delay(4000, cancelationToken).Wait();

                this.lodTriggerCount++;
                foreach (string item in Enum.GetNames(typeof(DayOfWeek)))
                {
                    result.Add(string.Format("LOD: {0} - {1}", lodTriggerCount, item));
                }
                return result;
            }
            catch
            {
                //exception is thrown when the task is canceled. Returning null does not affect the ItemsSource.
                return null;
            }
        });

        for (int i = 0; i < 14; i++)
        {
            Source.Add(string.Format("Item {0}", i));
        }
    }
}

Then, define RadListView instance and bind its ItemsSource to the data in the viewmodel:

<telerikDataControls:RadListView x:Name="listView"
                                 IsLoadOnDemandEnabled="True"
                                 ItemsSource="{Binding Source}"
                                 LoadOnDemandMode="Automatic" />

You would also need to define the listview namespace:

xmlns:telerikDataControls="clr-namespace:Telerik.XamarinForms.DataControls;assembly=Telerik.XamarinForms.DataControls"

Finally, set the ViewModel as BindingContext in the page constructor:

this.BindingContext = new ListViewModel();

Using LoadOnDemand Event

Another way to handle loading more items is via the LoadOnDemand event. This event is being raised on a UI thread, so in the event handler you can add items right away or get the data asynchronously:

  • In case data is available right away, you just need to add the items to the ListView ItemsSource in the LoadOnDemand event handler;

  • In case an async operation is required, you need to notify the ListView that the loading indicator should be displayed by setting the IsLoadOnDemandActive property of the ListView to true. Then an async call can be initiated to get the data. When the new items are ready, you'd need to set the IsLoadOnDemandActive property to False, again to notify the ListView that load-on-demand operation is completed.

Again, this approach works with both Automatic and Manual loading modes.

Let's have the following ListView definition:

<telerikDataControls:RadListView x:Name="listView"
                                 IsLoadOnDemandEnabled="True"
                                 LoadOnDemand="ListView_LoadOnDemand"
                                 LoadOnDemandMode="Automatic" />

You would also need to define the listview namespace:

xmlns:telerikDataControls="clr-namespace:Telerik.XamarinForms.DataControls;assembly=Telerik.XamarinForms.DataControls"

Set ListView itemsSource in page constructor:

this.source = new ObservableCollection<string>();
for (int i = 0; i < 14; i++)
{
    source.Add(string.Format("Item {0}", i));
}
this.listView.ItemsSource = this.source;

Then add the following event handler:

private ObservableCollection<string> source;
private int lodCounter = 0;

private async void ListView_LoadOnDemand(object sender, EventArgs e)
{
    // If you need to get new data asynchronously, you must manually update the loading status.
    this.listView.IsLoadOnDemandActive = true;

    IEnumerable<string> newItems = await this.GetNewItems();
    foreach (string newItem in newItems)
    {
        this.source.Add(newItem);
    }

    this.listView.IsLoadOnDemandActive = false;
}

private async Task<IEnumerable<string>> GetNewItems()
{
    this.lodCounter++;
    await Task.Delay(4000);  // Mimic getting data from server asynchronously.
    return Enum.GetNames(typeof(DayOfWeek)).Select(day => string.Format("LOD: {0} - {1}", this.lodCounter, day));
}

Using LoadOnDemand Command

This approach is similar to the one with using the LoadOnDemand event, just in this case the load-on-demand is handled in the ViewModel through the exposed by RadListView LoadOnDemandUserCommand. In the Execute method of the command you can add items right away or get the data asynchronously.

  • In case data is available right away, you just need to add the items to the ListView ItemsSource in the LoadOnDemand command Execute method;

  • In case an async operation is required, you need to notify the ListView that the loading indicator should be displayed by setting the IsLoadOnDemandActive property of the ListView to true. Then an async call can be initiated to get the data. When the new items are ready, you'd need to set the IsLoadOnDemandActive property to False, again to notify the ListView that load-on-demand operation is completed. You can control the behavior of IsLoadOnDemandActive through a binding to a boolean property in the ViewModel class.

You can use LoadOnDemandUserCommand with both "Automatic" and "Manual" loading mode depending on the concrete requirements.

First, let's create a ViewModel class with a LoadItemsCommand as well as IsLoadingMoreItems bool property:

public class ListViewModel : NotifyPropertyChangedBase
{
    private bool isLoadingMoreItems;
    private int lodCounter = 0;

    public ListViewModel()
    {
        this.Source = new ObservableCollection<string>();
        for (int i = 0; i < 14; i++)
        {
            this.Source.Add(string.Format("Item {0}", i));
        }
        this.LoadItemsCommand = new Command(this.LoadItemsCommandExecute);
    }

    public ObservableCollection<string> Source { get; }
    public ICommand LoadItemsCommand { get; set; }

    public bool IsLoadingMoreItems
    {
        get { return this.isLoadingMoreItems; }
        set { this.UpdateValue(ref this.isLoadingMoreItems, value); }
    }

    private async void LoadItemsCommandExecute(object obj)
    {
        // If you need to get new data asynchronously, you must manually update the loading status.
        this.IsLoadingMoreItems = true;

        IEnumerable<string> newItems = await this.GetNewItems();
        foreach (string newItem in newItems)
        {
            this.Source.Add(newItem);
        }

        this.IsLoadingMoreItems = false;
    }

    private async Task<IEnumerable<string>> GetNewItems()
    {
        this.lodCounter++;
        await Task.Delay(4000);  // Mimic getting data from server asynchronously.
        return Enum.GetNames(typeof(DayOfWeek)).Select(day => string.Format("LOD: {0} - {1}", this.lodCounter, day));
    }
}

Define the RadListView instance in XAML with the ListViewUserCommand defined as well as the IsLoadOnDemandActive property bound to the boolean property in the ViewModel:

<telerikDataControls:RadListView x:Name="listView"
                                 ItemsSource="{Binding Source}"
                                 IsLoadOnDemandEnabled="True"
                                 IsLoadOnDemandActive="{Binding IsLoadingMoreItems}"
                                 LoadOnDemandMode="Manual">
    <telerikDataControls:RadListView.Commands>
        <telerikListViewCommands:ListViewUserCommand Id="LoadOnDemand" 
                                                     Command="{Binding LoadItemsCommand}" />
    </telerikDataControls:RadListView.Commands>
</telerikDataControls:RadListView>

You would also need to define the following namespaces:

xmlns:telerikDataControls="clr-namespace:Telerik.XamarinForms.DataControls;assembly=Telerik.XamarinForms.DataControls"
xmlns:telerikListViewCommands="clr-namespace:Telerik.XamarinForms.DataControls.ListView.Commands;assembly=Telerik.XamarinForms.DataControls"

Finally, set the ViewModel as BindingContext in the page constructor:

this.BindingContext = new ListViewModel();

Advanced options

Control the number of preloaded items

This feature works in conjunction with LoadOnDemandMode.Automatic mode of the listview. You can control the number of minimum items loaded ahead through listview LoadOnDemandBufferItemsCount property. By default it is set to 10 item. When the listview requests an item in the buffer it will trigger new loading batch.

Change the appearance of Manual load button

This feature works in conjunction with LoadOnDemandMode.Manual mode of the listview You can control load more button content through the LoadOnDemandItemTemplate property.

<telerikDataControls:RadListView.LoadOnDemandItemTemplate>
    <DataTemplate>
        <Grid BackgroundColor="Red">
            <Label FontSize="24"
                   HorizontalOptions="Center"
                   Text="Load more items"
                   TextColor="Black" />
        </Grid>
    </DataTemplate>
</telerikDataControls:RadListView.LoadOnDemandItemTemplate>

Change the appearance of Manual loading indicator

This feature works in conjunction with LoadOnDemandMode.Manual mode of the listview You can control the loading indicator content through the LoadingOnDemandItemTemplate property.

<telerikDataControls:RadListView.LoadingOnDemandItemTemplate>
    <DataTemplate>
        <Grid BackgroundColor="Green">
            <Label FontSize="24"
                   HorizontalOptions="Center"
                   Text="Loading..."
                   TextColor="White" />
        </Grid>
    </DataTemplate>
</telerikDataControls:RadListView.LoadingOnDemandItemTemplate>

See Also

In this article
Not finding the help you need? Improve this article