代码之家  ›  专栏  ›  技术社区  ›  jfmg

ReactiveTableViewSource<TSource>如何工作?

  •  2
  • jfmg  · 技术社区  · 8 年前

    在我们的应用程序中,我们使用ReactiveUI来遵循MVVM模式。在一个视图中,我们希望显示UITableView。数据通常传递到UITableView。源代码,但我们使用ReactiveUI ReactiveTableViewSource<TSource> .

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

    我们现在拥有的是在UIView中创建一个表,如下所示:

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

    顺便问一下:细胞的作用是什么?

    此外,我们有一个Table源类,如下所示:

    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)
    

    在我的视图模型中,我有一个正在更新我的反应列表的服务。看起来是这样的:

    public sealed class MyService : ReactiveObject, IMyService
    {
      public IReactiveList<MyListObject> MyReactiveList { get; }
    
      public async Task UpdateMyReactiveListAsync() {//...}
    

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

    3 回复  |  直到 8 年前
        1
  •  3
  •   Paul Reichelt    8 年前

    使用ReactiveTableViewSource非常简单:

    只需将列表与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

        2
  •  2
  •   Kuroro    8 年前

    也许你错过了这个 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 => { });
    
        3
  •  1
  •   Lapinou    5 年前

    只需使用ReactiveUI版本9.16.6进行一次小更新:

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

    • =>我的ViewController继承自ReactiveViewController
    • =>我的CityViewModel继承自ReactiveObject
    • =>我的CityItemViewModel继承自ReactiveObject
    • =>我的城市表视图单元格继承自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);
            }
    

    希望能帮助别人;)