ReactiveTableViewSource<TSource> 是如何工作的?

How does ReactiveTableViewSource<TSource> work?

在我们的应用中,我们使用 ReactiveUI 来遵循 MVVM 模式。在一个视图中,我们想显示一个 UITableView。数据通常传递给 UITableView.Source 但对于 ReactiveUI 我们使用 ReactiveTableViewSource<TSource>.

我不明白的是如何将我在 ReactiveList 中的视图模型中获得的数据绑定到 ReactiveTableViewSource

我们现在拥有的是在 UI 视图中创建一个 table,如下所示:

Table = new UITableView(UIScreen.MainScreen.Bounds);
Table.Source = new TableSource(Table, MyReactiveList, (NSString) CellIdentifier, _cellHeight, cell => Debug.WriteLine(cell));

顺便说一句:单元格操作的用途是什么?

此外,我们还有一个 Table 来源 class,如下所示:

internal sealed class TableSource : ReactiveTableViewSource<MyListObject>
{
  public TableSource(UITableView tableView, IReactiveNotifyCollectionChanged<MyListObject> collection, NSString cellKey, float sizeHint, Action<UITableViewCell> initializeCellAction = null) : base(tableView, collection, cellKey, sizeHint, initializeCellAction)

在我的视图模型中,我有一个正在更新我的 ReactiveList 的服务。它看起来像这样:

public sealed class MyService : ReactiveObject, IMyService
{
  public IReactiveList<MyListObject> MyReactiveList { get; }

  public async Task UpdateMyReactiveListAsync() {//...}

我在哪里将 table 源绑定到 ReactiveList?我在哪里订阅活动?是否有任何我可能遗漏的文档或示例代码?

可能你错过了这个https://github.com/reactiveui/ReactiveUI/blob/275eca3dc2e5fc93bddb137e60be32885f788688/docs/basics/rx-cocoa-delegates.md

要订阅事件,您可以分配一个 UITableViewDelegateRx

var tvd = new UITableViewDelegateRx ();
Table.Delegate = tvd;
tvd.RowSelectedObs.Subscribe (c => { });

使用 ReactiveTableViewSource 非常简单:

只需将 List 与您的 UITableView 连接起来

var tableView = new UITableView ();

// Bind the List agains the table view
// SampleObject is our model and SampleCell the cell
ViewModel.WhenAnyValue (vm => vm.Items).BindTo<SampleObject, SampleCell> (tableView, 46, cell => cell.Initialize());

然后创建一个自定义单元格,您可以在其中将模型数据绑定到单元格。

public class SampleCell : ReactiveTableViewCell, IViewFor<SampleObject>
{
    public SampleCell () : base() { }
    public SampleCell (IntPtr handle) : base(handle) { }

    private SampleObject _viewModel;
    public SampleObject ViewModel
    {
        get { return _viewModel; }
        set { this.RaiseAndSetIfChanged (ref _viewModel, value); }
    }

    object IViewFor.ViewModel
    {
        get { return ViewModel; }
        set { ViewModel = value as SampleObject; }
    }

    public void Initialize()
    {
        this.WhenAnyValue (v => v.ViewModel.Name).BindTo (
            this,
            v => v.TextLabel.Text);
    }
}

您可以在此处找到一个引人注目的示例:https://github.com/reicheltp/ReactiveTableViewSource-Sample

2016/03/09 更新:最好在单独的 Initialize 方法中进行绑定,以防止多次调用。

如果你有更多问题可以在推特上问我:@reicheltp

只是为了使用 ReactiveUI 版本 9.16.6 进行小更新:

示例列出了一些城市及其相应的邮政编码。

  • => 我的 ViewController 继承自 ReactiveViewController
  • => 我的 CityViewModel 继承自 ReactiveObject
  • => 我的 CityItemViewModel 继承自 ReactiveObject
  • => 我的 CityTableViewCell 继承自 ReactiveTableViewCell

    public class CityViewModel : ReactiveObject
    {
        private ICityService CityService { get; }
    
        private SourceCache<CityItemViewModel, int> _citiesCache;
        private IObservable<IChangeSet<CityItemViewModel, int>> _citiesOperations => _citiesCache.Connect();
    
        public readonly ReadOnlyObservableCollection<CityItemViewModel> Cities;
    
        public CityViewModel(ICityService cityService)
        {
            CityService = cityService;
        }
    
        #region CityViewModelCommand
        public ReactiveCommand<CityItemViewModel, Unit> CityClickCommand { get; }
        #endregion
    
        private async Task<IEnumerable<CityItemViewModel>> SearchCitiesAsync(string searchText, CancellationToken token)
        {
            IEnumerable<CityItemViewModel> items;
    
            if (string.IsNullOrEmpty(searchText))
                items = await CityService.ToListWithCountryCodeAsync(cancellationToken: token);
            else
                items = await CityService.ToListBySearchWithCountryCodeAsync(searchText, cancellationToken: token);
    
            _citiesCache.Edit(innerList =>
            {
                innerList.Clear();
                innerList.AddOrUpdate(items);
            });
    
            return items;
        }
    }
    
    public class CityItemViewModel : ReactiveObject
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string PostalCode { get; set; }
        public override string ToString()
            => $"[CityItemViewModel: Id={Id}, Name={Name}, PostalCode={PostalCode}]";
    
        public CityItemViewModel() : base()
        {
    
        }
    }
    

在我的 ViewController 的 ViewDidLoad 方法中:

 this.WhenActivated((cleanup) =>
            {
                this.Bind(ViewModel,
                        x => x.SearchText,
                        x => x.searchBar.Text)
                    .DisposeWith(cleanup);

                this.WhenAnyValue(v => v.ViewModel.Cities)
                    .BindTo<CityItemViewModel, CityTableViewCell>(tableView, CityTableViewCell.Key, 50, cell => cell.Initialize(),
                        source => source.ElementSelected.InvokeCommand(ViewModel.CityClickCommand))
                    .DisposeWith(cleanup);
            });

在我的 UITableViewCell 的 Initialize 方法中:

public void Initialize()
        {
            this.WhenAnyValue(v => v.ViewModel.Name)
                .Subscribe(name => cityLabel.Text = name);

            this.WhenAnyValue(v => v.ViewModel.PostalCode)
                .Subscribe(x => postalCodeLabel.Text = x);
        }

希望能帮到别人 ;)