В настоящее время я создаю секционированный ListView в формах Xamarin, в котором я хочу динамически обновлять список по мере изменения наблюдаемого источника.
Приведенный ниже код работает, пока я не сгенерирую новый набор развертываний в наблюдаемом AllDeployments. Затем я получаю ArgumentOutOfBoundsException из базового представления списка, пытаясь обновить себя.
Я полагаю, что это связано с неожиданным изменением строк в каждом разделе? Кто-нибудь может увидеть, что я сделал не так?
Тот же код работает, если я обмениваюсь SourceCache с SourceList и соответствующим методом Edit.
class MockDeploymentService : IDeploymentsService
{
public IObservable<IEnumerable<Deployment>> AllDeployments {
get
{
DateTime date = DateTime.Now;
var deployments = new Deployment[]
{
new Deployment()
{
Id = "1",
Name = "One",
},
new Deployment()
{
Id = "2",
Name = "Two",
DeploymentDate = date
},
new Deployment()
{
Id = "3",
Name = "Three",
}
};
var deployments2 = new Deployment[]
{
new Deployment()
{
Id = "1",
Name = "One",
},
new Deployment()
{
Id = "2",
Name = "Two",
DeploymentDate = date
},
new Deployment()
{
Id = "3",
Name = "Three",
DeploymentDate = date
}
};
return Observable.Timer(DateTimeOffset.Now.AddSeconds(10))
.SelectMany(_ => Observable.Return(deployments2))
.StartWith(deployments);
}
}
}
public interface IDeploymentsService
{
IObservable<IEnumerable<Deployment>> AllDeployments { get; }
}
public class TableSection<T> : ObservableCollectionExtended<T>
{
public TableSection(string title, IEnumerable<T> items) : base(items)
{
Title = title;
}
public string Title { get; private set; }
}
public class DeploymentsPageViewModel : ViewModelBase
{
private readonly ISourceCache<DeploymentCellViewModel, string> _deploymentSourceCache;
public ReadOnlyObservableCollection<TableSection<DeploymentCellViewModel>> DeploymentViewModels { get; }
public DeploymentsPageViewModel(IDeploymentsService deploymentsService)
{
_deploymentSourceCache = new SourceCache<DeploymentCellViewModel, string>((x) => x.Deployment.Id);
deploymentsService.AllDeployments
.Do((IEnumerable<Deployment> deployments) =>
{
var oldItemIds = _deploymentSourceCache.Items.Select((x) => x.Deployment.Id);
var newItemIds = deployments.Select((x) => x.Id);
var deletedKeys = oldItemIds.Where((x) => !newItemIds.Contains(x));
_deploymentSourceCache.Edit((editableCache) =>
{
editableCache.RemoveKeys(deletedKeys);
editableCache.AddOrUpdate(TransformToViewModel(deployments));
});
})
.Subscribe()
.DisposeWith(subscriptionDisposables);
_deploymentSourceCache
.Connect()
// Hacky temporary way of grouping deployments
.GroupWithImmutableState((arg) => arg.Deployment.DeploymentDate == null ? "Not Deployed" : "Deployed")
.Transform((grouping) =>
{
return new TableSection<DeploymentCellViewModel>(grouping.Key, grouping.Items);
})
.Bind(out var deploymentViewModels)
.Subscribe()
.DisposeWith(subscriptionDisposables);
DeploymentViewModels = deploymentViewModels;
}
private IEnumerable<DeploymentCellViewModel> TransformToViewModel(IEnumerable<Deployment> deployments)
{
return deployments.Select((x) => new DeploymentCellViewModel(x));
}
}