ReactiveList更新似乎没有在UITableView中第一次正确编组

时间:2017-07-23 17:51:48

标签: uitableview xamarin xamarin.ios reactiveui

我在刷新UITableView时遇到问题,至少第一次ViewWillAppear,有时(很少)可能会挂起应用程序。当我离开UIViewController并更改标签项并导航回来时,一切都开始在整个生命周期中完美运行..

拥有如下的ReactiveTableViewSource。

public class ATableViewSource : ReactiveTableViewSourceBase<IAViewModel>
{
    WeakReference<AListViewController> _weakContainer;
    Lazy<AListViewController> _lazyContainerViewController;

    AListViewController Container => _lazyContainerViewController.Value;

    public ATableViewSource(AListViewController container,
                            UITableView tableView,
                            IReactiveNotifyCollectionChanged<IAViewModel> collection)
        : base(tableView, collection,
                ATableViewCell.Key,
                ATableViewCell.Height,
                ATableViewCell.Height)
    {
        _weakContainer = new WeakReference<AListViewController>(container);
        tableView.RegisterNibForCellReuse(ATableViewCell.Nib, ATableViewCell.Key);

        _lazyContainerViewController = new Lazy<AListViewController>(() =>
        {
            AListViewController _container;
            _weakContainer.TryGetTarget(out _container);
            return _container;
        });
    }

    public override void RowSelected(UITableView tableView, NSIndexPath indexPath)
    {
        base.RowSelected(tableView, indexPath);

        tableView.DeselectRow(indexPath, false);
        var item = ItemAt(indexPath) as IAViewModel;
        if (item.IsNotNull())
        {
            AViewController viewController = new AViewController(item);
          Container.NavigationController.PushViewController(viewController, true);
        }
    }
}

在AListViewController.ViewDidLoad中,我有这个设置。

ATableViewSource _viewSource;

public override void ViewDidLoad()
{
    base.ViewDidLoad();

    TableView.RowHeight = UITableView.AutomaticDimension;
    TableView.EstimatedRowHeight = 350.0f;
    TableView.ContentInset = new UIEdgeInsets(8.0f, 0.0f, 8.0f, 0.0f);

    _viewSource = new ATableViewSource(this, TableView, ViewModel.TheReactiveList);
    TableView.Source = _viewSource;
}

在ViewWillAppear中,我总是刷新数据(ViewModel.TheReactiveList)。

public override void ViewWillAppear(bool animated)
{
    base.ViewWillAppear(animated);

    ViewModel.RefreshTheReactiveList();
}

AViewModel设置。

public class TheListViewModel : SchedulersViewModelBase, ITheListViewModel
{
    public ReactiveList<IAViewModel> TheReactiveList { get; } = new ReactiveList<IAViewModel> { ChangeTrackingEnabled = true };

    protected readonly IDataService DataService;

    public TheListViewModel(IScheduler mainScheduler,
                            IScheduler taskPoolScheduler,
                            IDataService dataService)
            : base(mainScheduler, taskPoolScheduler)
    {
        DataService = dataService;
    }

    public void RefreshTheReactiveList()
    {
        DataService.RefreshData()
                    .SubscribeOn(MainScheduler)
                    .ObserveOn(MainScheduler)
                    .Subscribe(ClearDataAndAddRange,
                                ex => AppObservables.Errors.OnNext(ex))
                    .DisposeWith(Disposables);
    }

    void ClearDataAndAddRange(IEnumerable<IAViewModel> data)
    {
        using (TheReactiveList.SuppressChangeNotifications())
        {
            TheReactiveList.Clear();
            TheReactiveList.AddRange(data);
        }
    }
}

我必须在这个用例中提到我有一个父UIViewController,它有两个子控制器,每个子控制器都有相同的设置(UITableView,ReactiveTableViewSource,ViewModel.ReactiveList),并且为他们的UIView容器控制隐藏状态,但是我注意到了类似的效果。带有一个UITableView的UIViewController最多需要3秒钟才能在UITableView中显示结果。

为了您的参考,我发布了下面的ReactiveTableViewSourceBase<TViewModel>,我很久以前就在互联网上发现了这一点,所以可能会产生怀疑。将基类更改为ReactiveTableViewSource<TViewModel>虽然没有任何区别。

public abstract class ReactiveTableViewSourceBase<TViewModel> : ReactiveTableViewSource<TViewModel>, IInformsEnd
{
    private readonly Subject<Unit> _requestMoreSubject = new Subject<Unit>();
    private readonly Subject<CGPoint> _scrollSubject = new Subject<CGPoint>();

    public IObservable<CGPoint> DidScroll
    {
        get { return _scrollSubject.AsObservable(); }
    }

    public IObservable<Unit> RequestMore
    {
        get { return _requestMoreSubject; }
    }

    public override void Scrolled(UIScrollView scrollView)
    {
        _scrollSubject.OnNext(scrollView.ContentOffset);
    }

    ~ReactiveTableViewSourceBase()
    {
        Console.WriteLine("Destorying " + GetType().Name);
    }

    protected ReactiveTableViewSourceBase(UITableView tableView, nfloat height, nfloat? heightHint = null)
            : base(tableView)
    {
        tableView.RowHeight = height;
        tableView.EstimatedRowHeight = heightHint ?? tableView.EstimatedRowHeight;
    }

    protected ReactiveTableViewSourceBase(UITableView tableView, IReactiveNotifyCollectionChanged<TViewModel> collection,
            Foundation.NSString cellKey, nfloat height, nfloat? heightHint = null, Action<UITableViewCell> initializeCellAction = null)
            : base(tableView, collection, cellKey, (float)height, initializeCellAction)
    {
        tableView.RowHeight = height;
        tableView.EstimatedRowHeight = heightHint ?? tableView.EstimatedRowHeight;
    }

    public override void WillDisplay(UITableView tableView, UITableViewCell cell, Foundation.NSIndexPath indexPath)
    {
        if (indexPath.Section == (NumberOfSections(tableView) - 1) &&
            indexPath.Row == (RowsInSection(tableView, indexPath.Section) - 1))
        {
            // We need to skip an event loop to stay out of trouble
            BeginInvokeOnMainThread(() => _requestMoreSubject.OnNext(Unit.Default));
        }
    }

    public override void RowSelected(UITableView tableView, Foundation.NSIndexPath indexPath)
    {
        var item = ItemAt(indexPath) as ICanGoToViewModel;
        if (item != null)
        {
            item.GoToCommand.Execute();
        }

        base.RowSelected(tableView, indexPath);
    }

    protected override void Dispose(bool disposing)
    {
        _requestMoreSubject.Dispose();
        _scrollSubject.Dispose();
        base.Dispose(disposing);
    }
}

public interface IInformsEnd
{
    IObservable<Unit> RequestMore { get; }
}

0 个答案:

没有答案