Ever since upgrading to Xamarin.Forms 1.3 I get the following exception when I try to populate my ListView from data retrieved from a REST apt
MonoTouch.Foundation.MonoTouchException: Objective-C exception thrown. Name: NSInternalInconsistencyException Reason: Invalid update: invalid number of rows in section 0. The number of rows contained in an existing section after the update (1) must be equal to the number of rows contained in that section before the update (4), plus or minus the number of rows inserted or deleted from that section (1 inserted, 0 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out).
I have seen a couple other references to this problem and seen the following solutions suggested:
1. Use List instead of ObservableCollection
2. Use Device.BeginInvokeOnMainThread to update collections from the UI thread
3. Call BindingBase.EnableCollectionSynchronization when setting up the collection
I have tried these all and they have not worked for me (or I have applied them incorrectly) so I am asking for the communities help with this.
Below is the relevant code as it was working in 1.2 but not in 1.3 (on iOS; Android works fine)
FolderViewPage.xaml.cs
protected override async void OnAppearing()
{
base.OnAppearing();
if(BindingContext != null)
return;
if (!RestClient.IsInitialized)
{
await Navigation.PushModalAsync(LoginPage.GetLoginPage(OnAppearing));
}
else
{
InitializeVm();
}
}
private void InitializeVm()
{
var vm = new FolderViewModel(_name);
_folderVm = vm;
BindingContext = _folderVm;
_folderVm.LoadFolder(_id);
FolderListView.ItemsSource = _folderVm.CredentialGroups;
}
FolderViewModel.cs
public ObservableCollection<CredentialListViewModel> CredentialGroups;
public FolderViewModel(string name)
{
FolderName = name ?? "Root";
IsEmpty = false;
CredentialGroups = new ObservableCollection<CredentialListViewModel>();
}
public async Task LoadFolder(Guid id)
{
IsBusy = true;
try
{
if (id == Guid.Empty)
{
IsRoot = true;
id = await RestClient.GetRootCredentialGroupId();
}
else
{
IsRoot = false;
}
//if id is not present here then something has gone wrong.
if (id == Guid.Empty)
{
MessagingCenter.Send(this, App.ErrorMessage, "Could not get root folder identifier");
return;
}
var group = await RestClient.GetCrendentialGroup(id);
CredentialGroups.Clear();
var vms = group.Children.OrderBy(c => c.Name).Select(CredentialListViewModel.FromGroup).Concat(group.Credentials.OrderBy(c => c.Name).Select(CredentialListViewModel.FromCredential));
foreach (var vm in vms)
{
CredentialGroups.Add(vm);
}
IsBusy = false;
if (!CredentialGroups.Any())
IsEmpty = true;
}
catch (TokenExpiredExecption)
{
MessagingCenter.Send(this, App.TokenExpiredMessage, new Action(() => LoadFolder(id)));
}
catch (BusinessWebException ex)
{
string message;
switch (ex.FailureCode)
{
case HttpStatusCode.BadRequest:
message = "Bad Request";
break;
case HttpStatusCode.Unauthorized:
message = "Authentication failed";
break;
case HttpStatusCode.Forbidden:
message = "You do not have access to this folder";
break;
case HttpStatusCode.NotFound:
message = id == Guid.Empty ? "Unable to locate root folder" : "Unable to locate this folder";
break;
case HttpStatusCode.InternalServerError:
message = "Internal server error";
break;
default:
message = "No further information available";
break;
}
MessagingCenter.Send(this, App.ErrorMessage, message);
}
catch (BusinessException ex)
{
MessagingCenter.Send(this, App.ErrorMessage, ex.Message);
}
}
Can anyone offer any assistance in this matter?