我觉得我做对了,但是不确定。我正在将对象异步加载到ViewModel中的ReactiveList中。通过Xamarin表单,我已经将列表绑定(bind)到Xamarin表单中ListView的ItemSource属性。我还有一个搜索框,它将清除ReactiveList并将新项目添加到ReactiveList。

第一次打开View时,没有任何交互会加载列表,并且禁用了绑定(bind)到ReactiveCommand的按钮,该按钮用于将更多项目加载到ReactiveList中。

第二次打开 View 时,ListView几乎立即在新的ViewModel中呈现项目,但是同样,交互似乎不起作用。但是,更改搜索框实际上会从ListView中清除项目,但不会添加项目。

此行为在iOS上。我是ReactiveUI 6.3.1和Xamarin Forms 1.3.2.6316。

这是简化的问题:

public class MyViewModel : ReactiveObject, IRoutableViewModel
{
    public MyViewModel(IScreen hostScreen = null)
    {
        HostScreen = hostScreen ?? Locator.Current.GetService<IScreen>();

        List = new ReactiveList<ItemViewModel>()
        {
            ChangeTrackingEnabled = true
        };

        //This never gets shown
        List.Add(new ItemViewModel()
        {
            Name = "TEST"
        });

        //Tried doing this on the main thread: same behavior
        LoadItemsCommand = ReactiveCommand.CreateAsyncTask(_ => GetItems()), RxApp.TaskpoolScheduler);

        LoadItemsCommand
            .ObserveOn(RxApp.MainThreadScheduler)
            .Subscribe(results =>
            {
                //debugger breaks here in EVERY case and successfully changes List but doesn't necessarily affect the view

                try
                {
                    List.AddRange(results.Select(e => new ItemViewModel()
                    {
                        Name = e.Name
                    }));
                }
                catch (Exception ex)
                {
                    //breakpoint does not break here.
                    Debug.WriteLine(ex.Message);
                    throw;
                }

            });

        //No exceptions here either
        LoadItemsCommand.ThrownExceptions
            .Select(ex => new UserError("Error", "Please check your Internet connection"))
            .Subscribe(Observer.Create<UserError>(x => UserError.Throw(x)));

        this.WhenAnyValue(e => e.SearchText).Subscribe(e => ResetPage());
    }

    private Task<IEnumerable<Item>> GetItems()
    {
        //asynchronously get items
        return ...;
    }

    private int ResetPage()
    {
        List.Clear();
        return 0;
    }

    [DataMember]
    public ReactiveList<ItemViewModel> List { get; private set; }

    private string _searchText;
    [DataMember]
    public string SearchText
    {
        get { return _searchText; }
        set { this.RaiseAndSetIfChanged(ref _searchText, value); }
    }

    public ReactiveCommand<IEnumerable<Item>> LoadItems { get; protected set; }

    public class ItemViewModel : ReactiveObject
    {
        public string Name { get; set; }
    }

    public string UrlPathSegment
    {
        get { return "Page"; }
    }

    public IScreen HostScreen { get; protected set; }


}

我的xaml:


  <StackLayout VerticalOptions="FillAndExpand" Orientation="Vertical">
    <Entry x:Name="_searchEntry" Placeholder="Search"></Entry>
    <ListView x:Name="_myListView" RowHeight="80">
      <ListView.ItemTemplate>
        <DataTemplate>
          <ViewCell>
            <StackLayout Orientation="Vertical" >
              <Label Text="{Binding Name}"></Label>
              <Label Text="{Binding Address}"></Label>
              <Label Text="{Binding PhoneNumber}"></Label>
            </StackLayout>
          </ViewCell>
        </DataTemplate>
      </ListView.ItemTemplate>
    </ListView>
    <Button x:Name="_loadMoreButton" Text="Load More" TextColor="White" BackgroundColor="#77D065"></Button>  </StackLayout>
</XamForms:ReactiveContentPage>

我的查看代码在后面:
using System;
using System.Reactive.Concurrency;
using System.Threading.Tasks;

using ReactiveUI;
using ReactiveUI.XamForms;

namespace views
{
    public partial class MyView : ReactiveContentPage<MyViewModel>
    {
        private IDisposable _disconnectHandler;

        public NearbyPlacesView()
        {
            InitializeComponent();

            this.Bind(this.ViewModel, model => model.SearchText, view => view._searchEntry.Text);
            this.OneWayBind(this.ViewModel, model => model.List, view => view._myListView.ItemsSource);
            this.BindCommand(this.ViewModel, model => model.LoadItemsCommand, view => view._loadMoreButton);
        }

        protected override void OnAppearing()
        {
            base.OnAppearing();

            //Is this the proper way to do this? seems
            _disconnectHandler = UserError.RegisterHandler(async error =>
            {
                RxApp.MainThreadScheduler.ScheduleAsync(async (scheduler, token) =>
                {
                    await DisplayAlert("Error", error.ErrorMessage, "OK");
                });

                return RecoveryOptionResult.CancelOperation;
            });

            //Load the items when the view appears. This doesn't feel right though.
            ViewModel.LoadItemsCommand.Execute(null);
        }

        protected override void OnDisappearing()
        {
            base.OnDisappearing();

            _disconnectHandler.Dispose();
            _disconnectHandler = null;
        }
    }
}

最佳答案

这似乎是Xamarin Forms或ReactiveUI的错误。该问题记录在这里:https://github.com/reactiveui/ReactiveUI/issues/806

我将public ReactiveList<ItemViewModel> List的类型更改为public ObservableCollection<ItemViewModel> List,从而解决了该问题。

10-05 21:15