title: Xamarin Forms ListView SelectedItem Binding Issue
body: <p>ListViews follow the ItemPicker/Selector pattern of UI controls. Generally speaking, these types of controls, regardless of their platform will have a SelectedItem, and an ItemsSource. The basic idea is that there is a list of items in the ItemsSource, and the SelectedItem can be set to one of those items. Some other examples are ComboBoxes (Silverlight/UWP/WPF), and Pickers (Xamarin Forms). </p>
  
  <p>In some cases, these controls are async ready, and in other cases, code needs to be written in order to handle scenarios where the ItemsSource is populated later than the SelectedItem. In our case, most of the time, the BindingContext (which contains the property bound to SelectedItem) will be set before the ItemsSource. So, we need to write code to allow this to function correctly. We have done this for ComboBoxes in Silverlight for example.</p>
  
  <p>In Xamarin Forms, the ListView control is not async ready, i.e. if the ItemsSource is not populated before the SelectedItem is set, the selected item will never be highlighted on the control. This is probably by design and this is OK. <strong>The point of this thread is to find a way make the ListView async ready so that the ItemsSource can be populated <em>after</em> the SelectedItem is set.</strong></p>
  
  <p>There should be straight forward work arounds that can be implemented on other platforms to achieve this, but there are a few bugs in the Xamarin Forms list view that make it seemingly impossible to work around the issue. The sample app I have created is shared between WPF and Xamarin Forms in order to show how the ListView behaves differently on each platform. The WPF ListView for example, is async ready. If the ItemsSource is populated after the DataContext is set on a WPF ListView, the SelectedItem will bind to the item in the list.</p>
  
  <p>In Xamarin Forms, I cannot consistently get SelectedItem two way binding on ListView to work. If I select an item in the ListView, it sets the property on my model, but if I set the property on my model, the item that should be selected is not reflected as being selected in the ListView. After the items have been loaded, when I set the property on my model, no SelectedItem is displayed. This is happening on UWP and Android. iOS remains untested.</p>
  
  <p>You can see the sample problem in this Git repo:
  <a href="https://ChristianFindlay@bitbucket.org/ChristianFindlay/xamarin-forms-scratch.git" rel="nofollow noreferrer">https://ChristianFindlay@bitbucket.org/ChristianFindlay/xamarin-forms-scratch.git</a> . Simply run the UWP, or Android sample, and click Async ListView. You can also run the XamarinFormsWPFComparison sample to see how the WPF version behaves differently.</p>
  
  <p>When you run the Xamarin Forms sample, you will see that there is no item selected after the items load. However in the WPF version, it is selected. Note: It's not highlighted blue, but it is slightly grey indicating that it is selected. This is where my problem is, and the reason I can't work around the async issue.</p>
  
  <p>Here is my code (<strong>clone repo for absolute latest code</strong>):</p>
  
  <pre><code>public class AsyncListViewModel : INotifyPropertyChanged
  {
      #region Fields
      private ItemModel _ItemModel;
      #endregion
  
      #region Events
      public event PropertyChangedEventHandler PropertyChanged;
      #endregion
  
      #region Public Properties
      public ItemModel ItemModel
      {
          get
          {
              return _ItemModel;
          }
  
          set
          {
              _ItemModel = value;
              PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(ItemModel)));
          }
      }
      #endregion
  }
  
  
  public class ItemModel : INotifyPropertyChanged
  {
      #region Fields
      private int _Name;
      private string _Description;
      #endregion
  
      #region Events
      public event PropertyChangedEventHandler PropertyChanged;
      #endregion
  
      #region Public Properties
      public int Name
      {
          get
          {
              return _Name;
          }
  
          set
          {
              _Name = value;
              PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Name)));
          }
      }
  
      public string Description
      {
          get
          {
              return _Description;
          }
  
          set
          {
              _Description = value;
              PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Description)));
          }
      }
      #endregion
  
      #region Public Methods
      public override bool Equals(object obj)
      {
          var itemModel = obj as ItemModel;
          if (itemModel == null)
          {
              return false;
          }
  
          var returnValue = Name.Equals(itemModel.Name);
  
          Debug.WriteLine($"An {nameof(ItemModel)} was tested for equality. Equal: {returnValue}");
  
          return returnValue;
      }
  
      public override int GetHashCode()
      {
          Debug.WriteLine($"{nameof(GetHashCode)} was called on an {nameof(ItemModel)}");
          return Name;
      }
  
      #endregion
  }
  
  public class ItemModelProvider : ObservableCollection&lt;ItemModel&gt;
  {
      #region Events
      public event EventHandler ItemsLoaded;
      #endregion
  
      #region Constructor
      public ItemModelProvider()
      {
          var timer = new Timer(TimerCallback, null, 3000, 0);
      }
      #endregion
  
      #region Private Methods
      private void TimerCallback(object state)
      {
          Device.BeginInvokeOnMainThread(() =&gt; 
          {
              Add(new ItemModel { Name = 1, Description = "First" });
              Add(new ItemModel { Name = 2, Description = "Second" });
              Add(new ItemModel { Name = 3, Description = "Third" });
              ItemsLoaded?.Invoke(this, new EventArgs());
          });
      }
      #endregion
  }
  </code></pre>
  
  <p>This is the XAML:</p>
  
  <pre><code>    &lt;Grid x:Name="TheGrid"&gt;
  
          &lt;Grid.Resources&gt;
              &lt;ResourceDictionary&gt;
                  &lt;local:ItemModelProvider x:Key="items" /&gt;
              &lt;/ResourceDictionary&gt;
          &lt;/Grid.Resources&gt;
  
          &lt;Grid.RowDefinitions&gt;
              &lt;RowDefinition /&gt;
              &lt;RowDefinition Height="100" /&gt;
          &lt;/Grid.RowDefinitions&gt;
  
          &lt;ListView x:Name="TheListView" Margin="4" SelectedItem="{Binding ItemModel, Mode=TwoWay}" ItemsSource="{StaticResource items}" HorizontalOptions="Center" VerticalOptions="Center" BackgroundColor="#EEEEEE" &gt;
  
              &lt;ListView.ItemTemplate&gt;
                  &lt;DataTemplate&gt;
  
                      &lt;ViewCell&gt;
  
                          &lt;Grid &gt;
  
                              &lt;Grid.RowDefinitions&gt;
                                  &lt;RowDefinition Height="20" /&gt;
                                  &lt;RowDefinition Height="20" /&gt;
                              &lt;/Grid.RowDefinitions&gt;
  
                              &lt;Label Text="{Binding Name}" TextColor="#FF0000EE" VerticalOptions="Center"  /&gt;
                              &lt;Label Text="{Binding Description}" Grid.Row="1"  VerticalOptions="Center" /&gt;
  
                          &lt;/Grid&gt;
  
  
                      &lt;/ViewCell&gt;
  
                  &lt;/DataTemplate&gt;
              &lt;/ListView.ItemTemplate&gt;
  
          &lt;/ListView&gt;
  
          &lt;ActivityIndicator x:Name="TheActivityIndicator" IsRunning="True" IsVisible="True" Margin="100" /&gt;
  
          &lt;StackLayout Grid.Row="1" Orientation="Horizontal"&gt;
              &lt;Label Text="Name: " /&gt;
              &lt;Label Text="{Binding ItemModel.Name}" /&gt;
              &lt;Label Text="Description: " /&gt;
              &lt;Label Text="{Binding ItemModel.Description}" /&gt;
              &lt;Button Text="New Model" x:Name="NewModelButton" /&gt;
              &lt;Button Text="Set To 2" x:Name="SetToTwoButton" /&gt;
          &lt;/StackLayout&gt;
  
      &lt;/Grid&gt;
  </code></pre>
  
  <p>Code Behind:</p>
  
  <pre><code>public partial class AsyncListViewPage : ContentPage
  {
      ItemModelProvider items;
      ItemModel two;
  
      private AsyncListViewModel CurrentAsyncListViewModel =&gt; BindingContext as AsyncListViewModel;
  
      public AsyncListViewPage()
      {
          InitializeComponent();
  
          CreateNewModel();
  
          items = (ItemModelProvider)TheGrid.Resources["items"];
          items.ItemsLoaded += Items_ItemsLoaded;
  
          NewModelButton.Clicked += NewModelButton_Clicked;
          SetToTwoButton.Clicked += SetToTwoButton_Clicked;
      }
  
      private void SetToTwoButton_Clicked(object sender, System.EventArgs e)
      {
          if (two == null)
          {
              DisplayAlert("Wait for the items to load", "Wait for the items to load", "OK");
              return;
          }
  
          CurrentAsyncListViewModel.ItemModel = two;
      }
  
      private void NewModelButton_Clicked(object sender, System.EventArgs e)
      {
          CreateNewModel();
      }
  
      private void CreateNewModel()
      {
          //Note: if you replace the line below with this, the behaviour works:
          //BindingContext = new AsyncListViewModel { ItemModel = two };
  
          BindingContext = new AsyncListViewModel { ItemModel = GetNewTwo() };
      }
  
      private static ItemModel GetNewTwo()
      {
          return new ItemModel { Name = 2, Description = "Second" };
      }
  
      private void Items_ItemsLoaded(object sender, System.EventArgs e)
      {
          TheActivityIndicator.IsRunning = false;
          TheActivityIndicator.IsVisible = false;
          two = items[1];
      }
  }
  </code></pre>
  
  <p><em>Note: if I change the method CreateNewModel to this:</em></p>
  
  <pre><code>    private void CreateNewModel()
      {
          BindingContext = new AsyncListViewModel { ItemModel = two };
      }
  </code></pre>
  
  <p><em>the SelectedItem is reflected on screen. This seems to indicate that the ListView is comparing items based on object reference as opposed to using the Equals method on the objects. I tend to think of this as a bug. But, this is not the only issue here, because if this were the only issue, then clicking the SetToTwoButton should yield the same result.</em></p>
  
  <p><strong>It is now clear that there are several bugs around this is Xamarin Forms. I have documented the repro steps here:
  <a href="https://bugzilla.xamarin.com/show_bug.cgi?id=58451" rel="nofollow noreferrer">https://bugzilla.xamarin.com/show_bug.cgi?id=58451</a></strong></p>