反应列表更新不';在UITableView中,似乎无法第一次正确编组
我在正确刷新UITableView时遇到问题,至少第一次出现视图时,有时(很少)甚至可能会挂起应用程序。当我通过更改选项卡项离开UIViewController并向后导航时,在整个生命周期中,一切都开始完美工作 具有如下所示的ReactiveTableViewSource反应列表更新不';在UITableView中,似乎无法第一次正确编组,uitableview,xamarin,xamarin.ios,reactiveui,Uitableview,Xamarin,Xamarin.ios,Reactiveui,我在正确刷新UITableView时遇到问题,至少第一次出现视图时,有时(很少)甚至可能会挂起应用程序。当我通过更改选项卡项离开UIViewController并向后导航时,在整个生命周期中,一切都开始完美工作 具有如下所示的ReactiveTableViewSource public class ATableViewSource : ReactiveTableViewSourceBase<IAViewModel> { WeakReference<AListViewCo
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);
}
}
}
在视图中,我总是刷新数据(ViewModel.TheReactiveList)
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);
}
}
}
公共类ListViewModel:SchedulerViewModelBase,ITheListViewModel
{
public ReactiveList TheReactiveList{get;}=new ReactiveList{ChangeTrackingEnabled=true};
受保护的只读IDataService数据服务;
公共视图模型(ISScheduler Main Scheduler,
IsScheduler taskPoolScheduler,
IDataService(数据服务)
:基本(mainScheduler、taskPoolScheduler)
{
数据服务=数据服务;
}
public void refreshtereactivelist()
{
DataService.RefreshData()
.SubscribeOn(主计划程序)
.ObserveOn(主调度器)
.订阅(ClearDataandAddress,
ex=>AppObservables.Errors.OnNext(ex))
.一次性使用(一次性使用);
}
无效ClearDataAndAddressRange(IEnumerable数据)
{
使用(TheReactiveList.SuppressChangeNotifications())
{
TheReactiveList.Clear();
TheReactiveList.AddRange(数据);
}
}
}
我必须提到,在这个用例中,我有一个父UIViewController和两个子控制器,每个子控制器都具有相同的设置(UITableView、ReactiveTableViewSource、ViewModel.ReactiveList),并且它们的UIView容器的隐藏状态是受控的,但我注意到UIViewController也有类似的效果,一个UITableView最多需要3秒钟才能在UITableView中显示结果
我在下面发布了ReactiveTableViewSourceBase
供您参考,我很久以前在互联网上就发现了这个问题,所以它可能很可疑。不过,将基类更改为ReactiveTableViewSource
并没有什么区别
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; }
}
公共抽象类ReactiveTableViewSourceBase:ReactiveTableViewSource,IInformsEnd
{
私有只读主题_requestmorepubject=新主题();
私有只读主题_scrollSubject=新主题();
公共IObservable卷
{
获取{return\u scrollSubject.AsObservable();}
}
公共IObservable请求更多
{
获取{return\u requestmorepubject;}
}
公共覆盖无效滚动(UIScrollView滚动视图)
{
_scrollSubject.OnNext(scrollView.ContentOffset);
}
~ReactiveTableViewSourceBase()
{
WriteLine(“Destorying”+GetType().Name);
}
受保护的ReactiveTableViewSourceBase(UITableView tableView,nfloat高度,nfloat?heightHint=null)
:基础(表格视图)
{
tableView.RowHeight=高度;
tableView.EstimatedRowHeight=高度提示??tableView.EstimatedRowHeight;
}
受保护的ReactiveTableViewSourceBase(UITableView tableView、IReactiveNotifyCollectionChanged collection、,
NSCONCELL CELKEY,NFLULT高度,NFLULT?HEEGHUNTITT = NULL,Actudio RealAlgEcEccult=空值)
:基础(tableView、集合、cellKey、(浮动)高度、initializeCellAction)
{
tableView.RowHeight=高度;
tableView.EstimatedRowHeight=高度提示??tableView.EstimatedRowHeight;
}
公共覆盖空WillDisplay(UITababVIEW TabLVIEW,UITabelVIEW cell cell,基础.NSIXDEXPATH索引路径)
{
if(indexPath.Section==(NumberOfSections(tableView)-1)&&
indexPath.Row==(RowsInSection(tableView,indexPath.Section)-1)
{
//我们需要跳过事件循环以避免麻烦
BeginInvokeOnMainThread(()=>_requestMoreSubject.OnNext(Unit.Default));
}
}
公共覆盖空行选择(UITababVIEW TabLVIEW,基础.NSIXDEXPATH索引路径)
{
var item=ItemAt(indexPath)作为ICanGoToViewModel;
如果(项!=null)
{
item.GoToCommand.Execute();
}
base.RowSelected(tableView,indexPath);
}
受保护的覆盖无效处置(布尔处置)
{
_requestMoreSubject.Dispose();
_scrollSubject.Dispose();
基地。处置(处置);
}
}
公共接口IInformsEnd
{
IObservable RequestMore{get;}
}
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);
}
}
}
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; }
}