如何使用具有Reactive UI的Xamarin Android将数据绑定到自定义ListView

我正在使用具有Reactive UI的Xamarin Android而不使用Xamarin Forms。 我有一个自定义ListView(我已将其布局定义为xaml)。 我不知道如何使用活动类中的OneWayBind方法将此控件绑定到ViewModel中的observableCollection

我写的是,

this.OneWayBind(ViewModel, x => x.OutletListing, x => x.List).DisposeWith(SubscriptionDisposables); 

但是给了,

System.ArgumentException:无法将System.Collections.ObjectModel.ObservableCollection1转换为Android.Widget.ListView。 要解决此问题,请注册IBindingTypeConverter

我在教程中看到Xamarin Forms已经使用了ItemSource属性。

任何人都可以为此提供解决方案。 提前致谢。

更新我不知道如何继续给出答案。 我想更多地了解这一点。

这是我的ViewModel类。

 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Diagnostics; using Android.App; using Android.Content; using Android.OS; using Android.Runtime; using Android.Views; using Android.Widget; using ReactiveUI; using System.Collections.ObjectModel; using System.Reactive.Linq; using Splat; using System.Reactive.Disposables; using System.Threading.Tasks; namespace DistributrIII.Mobile.Droid.ViewModels { public class StockTakeVM : ReactiveObject { protected Lazy ViewModelBindings = new Lazy(() => new CompositeDisposable()); public void RegisterObservables() { StockItemListing = new ReactiveList(); this.LoadStockItems = ReactiveCommand.CreateFromTask<FilterParams, List>( async filter => { System.Diagnostics.Debug.WriteLine("Load StockItemListing #1"); var r = await GetStockItemListing(filter); return r; }, Observable.Return(true)) .DisposeWith(ViewModelBindings.Value); this.LoadStockItems.ThrownExceptions .Subscribe(ex => { System.Diagnostics.Debug.WriteLine("Load StockItemListing Failed"); }); this.LoadStockItems .ObserveOn(RxApp.MainThreadScheduler) .Subscribe(result => { StockItemListing.Clear(); foreach (var item in result) StockItemListing.Add(item); }); } async Task<List> GetStockItemListing(FilterParams filter) { List items = new List() { new StockItemListingResult { StockItemName = "PORK SAUSAGES (ECONOMY) 500G", StockItemCode = "CODE: J3103386", StockItemAmt = "150" }, new StockItemListingResult { StockItemName = "COLLAR BACON 500G", StockItemCode = "CODE: J3155667", StockItemAmt = "152" }, new StockItemListingResult { StockItemName = "COLLAR BACON 1KG", StockItemCode = "CODE: J2344545", StockItemAmt = "200" }, new StockItemListingResult { StockItemName = "PORK CHIPPOLATAS 1KG", StockItemCode = "CODE: J31038779", StockItemAmt = "378" }, new StockItemListingResult { StockItemName = "PORK SAUSAGES (ECONOMY) 500G", StockItemCode = "CODE: J3103386", StockItemAmt = "23" }, new StockItemListingResult { StockItemName = "PORK SAUSAGES (ECONOMY) 500G", StockItemCode = "CODE: J3103386", StockItemAmt = "454" }, new StockItemListingResult { StockItemName = "COLLAR BACON 500G", StockItemCode = "CODE: J3155667", StockItemAmt = "123" }, new StockItemListingResult { StockItemName = "COLLAR BACON 1KG", StockItemCode = "CODE: J2344545", StockItemAmt = "675" }, new StockItemListingResult { StockItemName = "PORK CHIPPOLATAS 1KG", StockItemCode = "CODE: J31038779", StockItemAmt = "11" }, new StockItemListingResult { StockItemName = "PORK SAUSAGES (ECONOMY) 500G", StockItemCode = "CODE: J3103386", StockItemAmt = "34" } }; return items; } // Observable Properties ReactiveList _stockItemListing; public ReactiveList StockItemListing { get { return _stockItemListing; } private set { this.RaiseAndSetIfChanged(ref _stockItemListing, value); } } ReactiveCommand<FilterParams, List> _loadStockItems; public ReactiveCommand<FilterParams, List> LoadStockItems { get { return _loadStockItems; } private set { this.RaiseAndSetIfChanged(ref _loadStockItems, value); } } public StockTakeVM() { RegisterObservables(); } } public class StockItemListingResult : ReactiveObject { Guid _stockItemId; public Guid Id { get { return _stockItemId; } set { this.RaiseAndSetIfChanged(ref _stockItemId, value); } } string _stockItemName; public string StockItemName { get { return _stockItemName; } set { this.RaiseAndSetIfChanged(ref _stockItemName, value); } } string _stockItemCode; public string StockItemCode { get { return _stockItemCode; } set { this.RaiseAndSetIfChanged(ref _stockItemCode, value); } } string _stockItemAmt; public string StockItemAmt { get { return _stockItemAmt; } set { this.RaiseAndSetIfChanged(ref _stockItemAmt, value); } } } } 

我的活动类如下

  using System; using System.Collections.Generic; using System.Linq; using System.Text; using Android.App; using Android.Content; using Android.OS; using Android.Runtime; using Android.Views; using Android.Widget; using ReactiveUI; using Android.Support.V4.Widget; using Android.Support.Design.Widget; using DistributrIII.Mobile.Droid.ViewModels; using DistributrIII.Mobile.Droid.Util; using System.Reactive.Disposables; using DistributrIII.Mobile.Droid.Models; using Android.Support.V7.Widget; using Android.Support.V7.App; using Splat; using Android.Support.V4.View; using System.Reactive.Linq; namespace DistributrIII.Mobile.Droid.Views.StockTake { [Activity(Label = "StockTakeActivity", MainLauncher = true, Theme = "@style/MainTheme")] public class StockTakeActivity : DistributrBaseActivity { private Android.Support.V7.Widget.SearchView _searchView; public ListView List { get; private set; } ReactiveList StockListItems; StockTakeScreenAdapter osadapter; List items = new List(); public StockTakeActivity() { this.ViewModel = new StockTakeVM(); this.StockListItems = new ReactiveList(); } protected override void OnCreate(Bundle savedInstanceState) { base.OnCreate(savedInstanceState); SetContentView(Resource.Layout.Activity_StockTake); this.Bind(ViewModel, x => x.StockItemListing, x => x.StockListItems); //checking whether change happens // StockListItems.ItemChanged // .Where(x => x.PropertyName == "StockItemAmt" && x.Sender.StockItemAmt) // .Select(x => x.Sender) // .Subscribe(x => { // Console.WriteLine("Make sure to save {0}!", x.DocumentName); //}); this.WhenAnyValue(view => view.ViewModel.StockItemListing) .Where(listing => listing != null) .Select(listing => new DistributrIII.Mobile.Droid.Util.ReactiveListAdapter(listing, Resource.Layout.Activity_StockTake)) .BindTo(this, view => view.List.Adapter); this.ViewModel.LoadStockItems.Execute(new FilterParams { NameFilter = "", Status = "All" }).Subscribe(); //List = FindViewById(Resource.Id.List); SetupReactiveLists(this); var toolbarST = FindViewById(Resource.Id.toolbarST); toolbarST.InflateMenu(Resource.Menu.StockTakeSearch); toolbarST.Title = "Stock Take"; } public void SetupReactiveLists(Activity context) { List = FindViewById(Resource.Id.List); foreach (var item in StockListItems) { StockItemModel stockitem = new StockItemModel { StockItemName = item.StockItemName, StockItemCode = item.StockItemCode }; items.Add(stockitem); } osadapter = new StockTakeScreenAdapter(this, items); List.Adapter = osadapter; List.ItemClick += OnListItemClick; } } 

这是我的Listadapter类。

 public class StockTakeScreenAdapter : BaseAdapter { List items; Activity context; public StockTakeScreenAdapter(Activity context, List items) : base() { this.context = context; this.items = items; } public override long GetItemId(int position) { return position; } public override StockItemModel this[int position] { get { return items[position]; } } public override int Count { get { return items.Count; } } public override View GetView(int position, View convertView, ViewGroup parent) { var item = items[position]; View view = convertView; if (view == null) view = context.LayoutInflater.Inflate(Resource.Layout.ViewCell_StockTake, null); view.FindViewById(Resource.Id.stockitem_name).Text = item.StockItemName; view.FindViewById(Resource.Id.stockitem_code).Text = item.StockItemCode; view.FindViewById(Resource.Id.stockitem_amt).Text = item.StockItemAmt; return view; 

}}

这是我的问题

  1. 我是否应该在Activity类中创建另一个响应List以进行绑定。
  2. 如果我更改了列表项的值,它是否更新列表(我希望使用另一个片段类更新列表项的值。)

我是RX的Android开发新手。 如果我搞砸了事情,请原谅我。 再次感谢。

您可以使用适配器在Android上完成此操作,就像没有Reactive Extensions一样。

如果您想使用带有RxUI的ListView,您将使用ReactiveListAdapter 。 不幸的是,这还没有真正记录,所以你可能想看一下源代码: https : //github.com/reactiveui/ReactiveUI/blob/develop/src/ReactiveUI/Platforms/android/ReactiveListAdapter.cs

要点是您使用提供数据的ReactiveList创建实例。 然后,适配器会监视此列表中的更改,以了解何时需要更新。

例:

 this.WhenAnyValue (view => view.ViewModel.OutletListing) .Where (listing => listing != null) .Select (listing => new ReactiveListAdapter (listing, MyViewCreator)) .BindTo (this, view => view.List.Adapter); 

MyViewCreator是一个委托,它接受列表中的初始ViewModel和父ViewGroup,因此您可以使用初始数据对行进行充气并返回生成的View。