title: Refresh Xamarin ListView on Add or Delete
body: <p>I am having difficulty with refreshing a Xamarin ListView once I have deleted a record, or added one from a different view.</p>
  
  <p>I have a view (RaceList.xaml) which lists races in an observable collection which it obtains from a ViewModel.</p>
  
  <p><strong>RaceList.xaml.cs</strong></p>
  
  <pre><code>using System.Collections.Generic;
  using TechsportiseApp.API;
  using TechsportiseApp.API.Models;
  using Xamarin.Forms;
  using Xamarin.Forms.Xaml;
  using TechsportiseApp.MainUI.ViewModels;
  using System;
  
  namespace TechsportiseApp.MainUI
  {
      [XamlCompilation(XamlCompilationOptions.Compile)]
      public partial class RaceList : ContentPage
      {
          public List&lt;Race&gt; Races { get; set; }
  
          public RaceList()
          {
              InitializeComponent();
  
              var viewModel = new RaceListViewModel();
              BindingContext = viewModel;
  
  
  
              ToolbarItems.Add(new ToolbarItem("New", "Add.png", async () =&gt;
              {
                  await Navigation.PushAsync(new RaceNew());
              }));
          }
  
          public void OnDelete(object sender, EventArgs e)
          {
              var menuitem = ((MenuItem)sender);
              var stringraceid = menuitem.CommandParameter.ToString();
              int raceid = Int32.Parse(stringraceid);
  
              RacesAPI.DeleteRace(raceid);
              MessagingCenter.Send(this, "RaceListChanged");
          }
  
          protected override void OnAppearing()
          {
              base.OnAppearing();
              RacesAPI.GetRaces();
              //LoadServerRegisteredCitizen is a method which i used to load items inside the listview        
          }
  
          async void Handle_ItemTapped(object sender, Xamarin.Forms.ItemTappedEventArgs e)
          {
              if (e.Item == null)
                  return;
              var race = e.Item as Race;
  
              await Navigation.PushAsync(new RaceView(race));
              //Deselect Item
              ((ListView)sender).SelectedItem = null;
          }
  
  
      }
  }
  </code></pre>
  
  <p><strong>RaceList.xaml</strong></p>
  
  <pre><code>&lt;?xml version="1.0" encoding="utf-8" ?&gt;
  &lt;ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
               xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
               x:Class="TechsportiseApp.MainUI.RaceList"
               Title="Races"&gt;
      &lt;!--SelectedItem="{Binding RaceSelected, Mode=TwoWay} "--&gt;
      &lt;ListView ItemsSource="{Binding Races}"
          ItemTapped="Handle_ItemTapped"
          SeparatorVisibility = "None"
          IsPullToRefreshEnabled="true" 
          RefreshCommand="{Binding RefreshCommand}" 
          IsRefreshing="{Binding IsBusy}"&gt;
  
          &lt;ListView.ItemTemplate&gt;
              &lt;DataTemplate&gt;
                  &lt;ViewCell&gt;
                      &lt;ViewCell.ContextActions&gt;
                         &lt;MenuItem Clicked="OnDelete" CommandParameter="{Binding Id}" Text="Delete" IsDestructive="True" /&gt;
                      &lt;/ViewCell.ContextActions&gt;
                      &lt;StackLayout&gt;
                          &lt;Label Text="{Binding Name}"  /&gt;
                          &lt;Label Text="{Binding RaceDate}" /&gt;
                          &lt;BoxView Color="#B2B2B2" HeightRequest="1" /&gt;
                      &lt;/StackLayout&gt;
                  &lt;/ViewCell&gt;
              &lt;/DataTemplate&gt;
          &lt;/ListView.ItemTemplate&gt;
      &lt;/ListView&gt;
  &lt;/ContentPage&gt;
  </code></pre>
  
  <p><strong>RaceListViewModel.cs</strong></p>
  
  <pre><code>using System;
  using System.Collections.Generic;
  using System.ComponentModel;
  using System.Threading.Tasks;
  using Newtonsoft.Json;
  using RestSharp;
  using TechsportiseApp.API.Models;
  using Xamarin.Forms;
  using TechsportiseApp.API;
  using System.Windows.Input;
  using System.Collections.ObjectModel;
  
  namespace TechsportiseApp.MainUI.ViewModels
  {
      public class RaceListViewModel : INotifyPropertyChanged
      {
          public RaceListViewModel()
          {
              _refreshCommand = new Command(RefreshList);
  
              MessagingCenter.Subscribe&lt;RaceListViewModel&gt;(this, "RaceListChanged", sender =&gt; {
                  Races = RacesAPI.GetRaces();
                  OnPropertyChanged("Id");
              });
          }
  
          public void RefreshList()
          {
              //Refreshes list on Pull to Refresh
             Races = RacesAPI.GetRaces();
          }
  
          int _id;
          public int Id
          {
              get
              {
                  return _id;
              }
              set
              {
                  if (_id != value)
                  {
                      _id = value;
                      // trigger some action to take such as updating other labels or fields
                      OnPropertyChanged("Id");
                  }
              }
          }
  
          int _name;
          public int Name
          {
              get
              {
                  return _name;
              }
              set
              {
                  if (_name != value)
                  {
                      _name = value;
  
                      // trigger some action to take such as updating other labels or fields
                      OnPropertyChanged("Name");
                  }
              }
          }
  
          private ObservableCollection&lt;Race&gt; _races;
          public ObservableCollection&lt;Race&gt; Races
          {
              get
              {
                  var racelist = RacesAPI.GetRaces();
                  IsBusy = false;
                  return racelist;
              }
              set
              {
                  if (_races != value)
                  {
                      _races = value;
                      // trigger some action to take such as updating other labels or fields
                      OnPropertyChanged("Races");
                  }
              }
          }
  
          private Race _raceSelected;
          public Race RaceSelected
          {
              get
              {
                  return RaceSelected;
              }
              set
              {
                  if (RaceSelected != value)
                  {
                      RaceSelected = value;
                      OnPropertyChanged("RaceSelected");
                  }
              }
          }
  
  
  
          private bool _isBusy;
          public bool IsBusy
          {
              get { return _isBusy; }
              set
              {
                  if (_isBusy == value)
                      return;
  
                  _isBusy = value;
                  OnPropertyChanged("IsBusy");
              }
          }
  
  
  
          public event PropertyChangedEventHandler PropertyChanged;
  
          protected virtual void OnPropertyChanged(string propertyName)
          {
              var changed = PropertyChanged;
              if (changed != null)
              {
                  PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
              }
          }
  
          Command _refreshCommand;
          public Command RefreshCommand
          {
              get
              {
                  return _refreshCommand;
              }
          }
      }
  }
  </code></pre>
  
  <p>On pressing the "Create" button in the toolbar, this takes me to a new View which shows a blank form, allowing me to fill in the data for a new race. When this is Saved, it pushes the JSON to my API and if successful it then redirects them to the edit page. </p>
  
  <p><strong>RaceNew.xaml</strong></p>
  
  <pre><code>&lt;?xml version="1.0" encoding="UTF-8"?&gt;
  &lt;ContentPage xmlns="http://xamarin.com/schemas/2014/forms" 
               xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" 
               xmlns:sys="clr-namespace:System;assembly=mscorlib"
               x:Class="TechsportiseApp.MainUI.RaceNew"
               Title="New Race"&gt;
      &lt;ContentPage.Content&gt;
      &lt;ScrollView  Orientation = "Vertical" VerticalOptions="StartAndExpand"&gt;
      &lt;StackLayout Padding="0,20,0,0"&gt;
          &lt;Label x:Name="labelName" Text="Name" /&gt;
              &lt;Entry x:Name="entryName"  /&gt;
          &lt;Label x:Name="labelDescription" Text="Description" /&gt;
              &lt;Editor x:Name="editorDescription"  /&gt;
         &lt;Label x:Name="labelContactName" Text="Contact Name" /&gt;
              &lt;Entry x:Name="entryContactName"  /&gt;
          &lt;Label x:Name="labelContactNumber" Text="Contact Number" /&gt;
              &lt;Entry x:Name="entryContactNumber" Keyboard="Telephone"  /&gt;
          &lt;Label x:Name="labelContactEmail" Text="ContactEmail" /&gt;
              &lt;Entry x:Name="entryContactEmail" Keyboard="Email"   /&gt;
          &lt;Label x:Name="labelRaceDate" Text="Race Date" /&gt;
                  &lt;DatePicker x:Name="datepickerRaceDate" Date="{Binding Source={x:Static sys:DateTime.Now}" Format="ddd d MMMM yyyy" /&gt;
          &lt;Label x:Name="labelRaceStartTime" Text="Race Time" /&gt;
                  &lt;TimePicker x:Name="timepickerRaceStartTime"  /&gt;
          &lt;Label x:Name="labelMaxEntries" Text="Max Entries" /&gt;
                  &lt;Entry x:Name="entryMaxEntries"  Keyboard="Numeric"  /&gt;
          &lt;Label x:Name="labelCurrentEntries" Text="Current Entries" /&gt;
                  &lt;Entry x:Name="entryCurrentEntries"  Keyboard="Numeric" /&gt;
          &lt;Label x:Name="labelIsOpenForEntries" Text="Open For Entries" /&gt;
              &lt;Switch x:Name="switchIsOpenForEntries"  /&gt;
          &lt;Label x:Name="labelIsPublished" Text="Published" /&gt;
              &lt;Switch x:Name="switchIsPublished"  /&gt;        
      &lt;/StackLayout&gt;
      &lt;/ScrollView&gt;
      &lt;/ContentPage.Content&gt;
  &lt;/ContentPage&gt;
  </code></pre>
  
  <p><strong>RaceNew.xaml.cs</strong></p>
  
  <pre><code>using System;
  using TechsportiseApp.API;
  using TechsportiseApp.API.Models;
  using Xamarin.Forms;
  using Xamarin.Forms.Xaml;
  
  namespace TechsportiseApp.MainUI
  {
      [XamlCompilation(XamlCompilationOptions.Compile)]
      public partial class RaceNew : ContentPage
      {
          public RaceNew()
          {
              InitializeComponent();
  
              ToolbarItems.Add(new ToolbarItem("Create", "", async () =&gt;
  
              {
                  var saverace = new Race();
                  saverace.ContactEmail = entryContactEmail.Text;
                  saverace.ContactName = entryContactName.Text;
                  saverace.ContactNumber = entryContactNumber.Text;
                  saverace.CurrentEntries = 0;
                  saverace.Description = editorDescription.Text;
                  saverace.IsOpenForEntries = switchIsOpenForEntries.IsToggled;
                  saverace.IsPublished = switchIsPublished.IsToggled;
                  saverace.IsComplete = false;
                  saverace.MaxEntries = System.Convert.ToInt32(entryMaxEntries.Text);
                  saverace.Name = entryName.Text;
                  saverace.RaceDate = datepickerRaceDate.Date;
  
                  var timestring = string.Format("{0:00}:{1:00}:{2:00}", timepickerRaceStartTime.Time.Hours, timepickerRaceStartTime.Time.Minutes, timepickerRaceStartTime.Time.Seconds);
                  saverace.RaceStartTime = timestring;
  
                  var response = RacesAPI.CreateRace(saverace);
                  if (response.Code == "Created")
                  {
                      saverace.Id = response.ReturnedId;
                      Navigation.InsertPageBefore(new RaceView(saverace), this);
                      await Navigation.PopAsync();
  
                  }
                  //Error response
                  else
                  {
                      await DisplayAlert("Error: " + response.Code, "There has been an error creating your race. " + response.Content, "OK");
                  }
              }));
          }
  
  
          async void OnBackButtonClicked(object sender, EventArgs e)
          {
              await Navigation.PopAsync();
          }
      }
  }
  </code></pre>
  
  <p>From this page I simply press the Back button and it returns me back to my RaceList view.</p>
  
  <p>The problem is, the list view doesn't refresh - it doesn't register that the new race is added.</p>
  
  <p>Furthermore, in my RaceList.xaml.cs you can see I also have a Delete button in use. When I delete the item from the list it doesn't refresh either!</p>
  
  <p>Any ideas?</p>