Why Doesn't My ListView Display The Added Items ?

DyaryDyary Member ✭✭
edited August 2018 in Xamarin.Forms

Hi.

# I am using a MVVM for a contact book app I am creating. I think I have setup everything right but the ListView doesn't show the items as it is supposed to be.

here is the MainPage.cs file:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:App4"
             x:Class="App4.MainPage">

    <StackLayout>

        <StackLayout Orientation="Horizontal" HorizontalOptions="Center">
            <Button  Text="Add" Clicked="buttonAdd_Clicked" WidthRequest="65" FontSize="15" HeightRequest="50"/>
            <Button  Text="Delete" Clicked="buttonDelete_Clicked" WidthRequest="80" HeightRequest="40" FontSize="15"/>
            <Button  Text="Update" Clicked="buttonUpdate_Clicked" WidthRequest="80" FontSize="15" HeightRequest="50"/>
        </StackLayout>
        <ListView  ItemsSource="{Binding  ObservableCollection}">
            <ListView.ItemTemplate >
                <DataTemplate>
                    <TextCell Text="{Binding Name}" Detail="{Binding Id}"/>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
    </StackLayout>

</ContentPage>

as you can see I have set the ItemSource property of the ListView to the ObservableCollection property of the MainPageViewModel class and using a TextCell I have bound the text and detail properties of the ListView to the Name and Id propertie s of the ContactViewModel class, which is what my ObservableCollection property is made of .

here is the MainPage.cs file

using SQLite;
using System;
using App4.Persistence;
using App4.ViewModels;
using Xamarin.Forms;

namespace App4
{

    public class Contact 
    {


        [PrimaryKey, AutoIncrement]
        public int Id { get; set; }


        [MaxLength(255)]
        public string Name { get; set; }

    }



    public partial class MainPage : ContentPage
    { 
        SQLiteAsyncConnection connection;



        public MainPage()
        {
            InitializeComponent();


            BindingContext = new  MainPageViewModel();

        } 

        protected  override void OnAppearing()
        {


            MainPageViewModel mainPageVM = new MainPageViewModel();
            mainPageVM.CreateConnection();

            base.OnAppearing();
        }

        private  void buttonAdd_Clicked(object sender, EventArgs e)
        {
           (BindingContext as MainPageViewModel).OnAddContact();
        }


        private  void  buttonDelete_Clicked(object sender, EventArgs e)
        {
            (BindingContext as MainPageViewModel).OnDelete();

        }

        private  void buttonUpdate_Clicked(object sender, EventArgs e)
        {
            (BindingContext as MainPageViewModel).OnUpdate();
        }


    }
}

I have set the biding context of the page to a new MainPageViewModel instance.

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Text;
using App4.Persistence;
using SQLite;
using Xamarin.Forms;


namespace App4.ViewModels
{
    public class MainPageViewModel : BaseViewModel
    {
        SQLiteAsyncConnection connection;



        public MainPageViewModel()
        {
            CreateConnection();
        }


        public ObservableCollection<ContactViewModel> ObservableCollection { get; set; }

        public async void OnAddContact()
        {
            var contact1 = new ContactViewModel() { Name = "Dyary " + DateTime.Now.Ticks };


            ObservableCollection.Add(contact1);

            await connection.InsertAsync(contact1);

        }

        public async void OnDelete()
        {
            var _contact = ObservableCollection[0];
            ObservableCollection.Remove(_contact);
           await connection.DeleteAsync(_contact);

        }

        public async void OnUpdate()
        {
            var contactUpdated = ObservableCollection[0];
            var _contactUpdated =  contactUpdated.Name += " Updated";
            connection.UpdateAsync((_contactUpdated));
        }

        public async void CreateConnection(  )
        {
            connection =  DependencyService.Get<ISQLiteDB>().GetConnection();

             await connection.CreateTableAsync<ContactViewModel>();

             var table = await connection.Table<ContactViewModel>().ToListAsync() ;

            ObservableCollection = new ObservableCollection<ContactViewModel>(table);
        }



    }
}

this is the MainPageViewModel.cs class
in the create conenction method I create a new SQLite connetion , create a table , then get the table and making it instantiation for the ObservableCollection property of the class.

Now in the constructor of this class I call the CreateConnection method.
then I I create a new instance of the MainPageViewModel in the OnAppearing method of the MainPage.cs which is supposed to run the constructor of the MainPageViewModel class , give me the connection I want, set the table created as the the ObservableCollection property. which in turn should populate the ListView with whatever was in the database but this doesn't happen.

Any suggestion guys ?

Answers

  • AdamMeaneyAdamMeaney USMember ✭✭✭✭✭
            public MainPage()
            {
                InitializeComponent();
    
    
                BindingContext = new  MainPageViewModel();
    
            } 
    
            protected  override void OnAppearing()
            {
    
    
                MainPageViewModel mainPageVM = new MainPageViewModel();
                mainPageVM.CreateConnection();
    
                base.OnAppearing();
            }
    

    You are not setting your new mainPageVM to your BindingContext. So nothing changes, as your BindingContext never experiences any change.

            protected  override void OnAppearing()
            {
                (BindingContext as MainPageViewModel).CreateConnection();
    
                base.OnAppearing();
            }
    

    This uses your existing Context to get the connection and get updated.

  • DyaryDyary Member ✭✭
    edited August 2018

    Thank you @AdamMeaney . I changed the code as you suggested. I still get nothing. any other suggestions?

    I even tied this so that I set the BindingContext to the Right instance of the MainPageViewModel :

    using SQLite;
    using System;
    using App4.Persistence;
    using App4.ViewModels;
    using Xamarin.Forms;
    using Xamarin.Forms.Platform.Android;
    
    namespace App4
    {
    
        public class Contact 
        {
            [PrimaryKey, AutoIncrement]
            public int Id { get; set; }
    
    
            [MaxLength(255)]
            public string Name { get; set; }
    
        }
    
        public partial class MainPage : ContentPage
        {
            public MainPageViewModel getMainPageVar { get; set; }
    
            public MainPage()
            {
                InitializeComponent();
                var x = new MainPageViewModel();
    
                getMainPageVar = x;
    
                BindingContext = getMainPageVar;
            } 
    
            protected  override void OnAppearing()
            {
                getMainPageVar.CreateConnection();
                base.OnAppearing();
            }
        }
    }
    
  • AdamMeaneyAdamMeaney USMember ✭✭✭✭✭

    Most importantly, if you are assigning a new collection to your ObservableCollection property, you need to have your ViewModel implement INotifyPropertyChanged. Most likely your BaseViewModel has some kind of NotifyPropertyChanged method to call in the setter of ObservableCollection to get that going.

    Examples can be found all over the internet if you don't have it in your base class.

Sign In or Register to comment.