此行为是在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();
List = new ReactiveList()
{
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(x => UserError.Throw(x)));
this.WhenAnyValue(e => e.SearchText).Subscribe(e => ResetPage());
}
private Task> GetItems()
{
//asynchronously get items
return ...;
}
private int ResetPage()
{
List.Clear();
return 0;
}
[DataMember]
public ReactiveList List { get; private set; }
private string _searchText;
[DataMember]
public string SearchText
{
get { return _searchText; }
set { this.RaiseAndSetIfChanged(ref _searchText, value); }
}
public ReactiveCommand> 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:
我认为代码隐藏:
using System;
using System.Reactive.Concurrency;
using System.Threading.Tasks;
using ReactiveUI;
using ReactiveUI.XamForms;
namespace views
{
public partial class MyView : ReactiveContentPage
{
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;
}
}
}