Проблемы с использованием секционного Xamarin Forms ListView с использованием ReactiveUI - PullRequest
0 голосов
/ 27 марта 2019

В настоящее время я создаю секционированный 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));
    }
}
...