我觉得我这样做是正确的,但我不确定。我异步地将对象加载到ViewModel中的ReactiveList中。通过Xamarin Forms,我将List绑定到Xamarin Forms中ListView的ItemSource属性。我还有一个搜索框,它将清除ReactiveList并将新项添加到ReactiveList。
第一次打开View时,没有任何交互使列表加载,并且禁用了一个绑定到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;
}
}
}
答案 0 :(得分:5)
这似乎是Xamarin Forms或ReactiveUI的错误。这里记录了这个问题:https://github.com/reactiveui/ReactiveUI/issues/806
我将public ReactiveList<ItemViewModel> List
的类型更改为修复此问题的public ObservableCollection<ItemViewModel> List
。
答案 1 :(得分:0)
您的ItemViewModel是一个ReactiveObject,但是您还没有正确编写setter。记住,你应该在setter中使用this.RaiseAndSetIfChanged来提升NPC。