Jaycee Evangelista
Jaycee Evangelista

Reputation: 1127

Xamarin.Forms: ListView not Displaying in Android

Good Day. I'm creating a simple Xamarin.Forms (Portable) application that allows me to create record of an Employee and saved it on a Database in Visual Studio. All records are being displayed to a ListView.

My application is doing fine when I run it on UWP. It displays the all the created records on a ListView properly.

But when I run it on Android Platform, it does not display any record in the ListView. I even tried to check on the Web API whether it returns a value or not. And I did get a value. Meaning, the problem is on Android Platform why it isn't displaying any record.

Have you encountered this problem? What do you think is the reason behind this? What can I do now? Sorry I'm just a newbie here in Xamarin. Hope you can help me. Thanks a lot.

These are some codes I have:

EmployeeRecordsPage.xaml

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
         xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
         x:Class="XamarinFormsDemo.EmployeeRecordsPage"
         xmlns:ViewModels="clr-namespace:XamarinFormsDemo.ViewModels;assembly=XamarinFormsDemo"
         xmlns:controls="clr-namespace:ImageCircle.Forms.Plugin.Abstractions;assembly=ImageCircle.Forms.Plugin.Abstractions"
         BackgroundImage="bg3.jpg"
         Title="List of Employees">


  <ContentPage.BindingContext>
    <ViewModels:MainViewModel/>
  </ContentPage.BindingContext>

  <StackLayout Orientation="Vertical">


    <ListView ItemsSource="{Binding EmployeesList}"
        HasUnevenRows="True"
        IsPullToRefreshEnabled="True"
        >
<ListView.ItemTemplate>
  <DataTemplate>
    <ViewCell>
      <Grid Padding="10" RowSpacing="10" ColumnSpacing="5">
        <Grid.RowDefinitions>
          <RowDefinition Height="Auto"/>
          <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
          <ColumnDefinition Width="Auto"/>
          <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>

        <controls:CircleImage Source="icon.png"
               HeightRequest="66"
               HorizontalOptions="CenterAndExpand"
               Aspect="AspectFill"
               WidthRequest="66"
               Grid.RowSpan="2"
               />


        <Label Grid.Column="1"
               Text="{Binding EMPLOYEE_NAME}"
               TextColor="#24e97d"
               FontSize="24"/>



      <Label Grid.Column="1"
              Grid.Row="1"
               Text="{Binding EMP_NUMBER}"
               TextColor="White"
               FontSize="18"
               Opacity="0.6"/>


        <Label Grid.Column="1"
            Grid.Row="2"
            Text="{Binding DEPT_COMP}"
             TextColor="White"
             FontSize="18"
             Opacity="0.6"/>



          </Grid>
        </ViewCell>
      </DataTemplate>
    </ListView.ItemTemplate>

  </ListView>


<StackLayout Orientation="Vertical"
         Padding="30,10,30,10"
         HeightRequest="20"
         BackgroundColor="#24e97d"
         VerticalOptions="Center"
         Opacity="0.5">
  <Label Text="© Copyright 2016   SMESOFT.COM.PH   All Rights Reserved "
         HorizontalTextAlignment="Center"
         VerticalOptions="Center"
         HorizontalOptions="Center" />
    </StackLayout>
  </StackLayout>



</ContentPage>

..

EmployeeViewModel.cs

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;
using XamarinFormsDemo.Models;
using XamarinFormsDemo.Services;

namespace XamarinFormsDemo.ViewModels
{
    public class MainViewModel : INotifyPropertyChanged
    {

        private List<Employee> _employeesList;
        private Employee _selectedEmployee = new Employee();




    public List<Employee> EmployeesList
    {
        get { return _employeesList; }
        set
        {
            _employeesList = value;
            OnPropertyChanged();
        }
    }



    public MainViewModel()
    {
        InitializeDataAsync();
    }

    private async Task InitializeDataAsync()
    {
        var employeesServices = new EmployeesServices();

        EmployeesList = await employeesServices.GetEmployeesAsync();
    }


    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        var handler = PropertyChanged;
        if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
    }

    }
}

..

EmployeesServices.cs

using Plugin.RestClient;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using XamarinFormsDemo.Models;

namespace XamarinFormsDemo.Services
{
   public class EmployeesServices
    {

    public async Task<List<Employee>> GetEmployeesAsync()
    {
        RestClient<Employee> restClient = new RestClient<Employee>();

        var employeesList = await restClient.GetAsync();

        return employeesList;

        }

    }
}

Upvotes: 0

Views: 2469

Answers (1)

jgoldberger - MSFT
jgoldberger - MSFT

Reputation: 6088

I think the issue is that you are not updating the ListView after you get your items with:

EmployeesList = await employeesServices.GetEmployeesAsync();

I would suggest using an ObservableCollection instead of a List. With an observable collection the ListView should get updated automatically when items in the ObservableCollection are added or deleted. So instead of:

private List<Employee> _employeesList;

try:

private ObservableCollection<Employee> _employeesList;

or you can just assign the ListView.ItemsSource to null and then back to the List<Employee> after you get your data:

EDIT: As noted by Jaycee, the following code to reset the ItemsSource should not be in the view model as the view model won't have access to listView. However the way to refresh the listView.ItemsSource is correct. The view model just needs to let the view know that the EmployeesList was updated and then you can reset the listView.ItemsSource in the code behind for the view. This could be done in a couple of ways I can think of. For instance you could have a delegate in the ViewModel that the view can provide the code implementation for or the view model could raise an event that the view can subscribe to. Basically you just have to let the view know that it needs to refresh its ListView's ItemsSource. But all of this could be avoided by using an ObservableCollection instead of a list as I noted previously.

EmployeesList = await employeesServices.GetEmployeesAsync();
listView.ItemsSource = null;
listView.ItemsSource = EmployeesList;

And to do the above you would have to give your ListView a name that you can use to reference it in code. YOu can set this name in the XAML for the ListView:

<ListView 
    ItemsSource="{Binding EmployeesList}"
    HasUnevenRows="True"
    IsPullToRefreshEnabled="True"
    x:Name="listView"
>

But the ObservableCollection would be the preferable option.

Upvotes: 3

Related Questions