我覺得我正在做這個正確的方式,但我不確定。我在我的ViewModel異步加載對象到ReactiveList中。通過Xamarin Forms,我已經將列表綁定到Xamarin Forms中的ListView的ItemSource屬性。我也有一個搜索框,它將清除ReactiveList並將新項目添加到ReactiveList。綁定ReactiveList <T> Xamarin形式的ListView
第一次打開視圖時,沒有任何交互操作會加載列表,並且綁定到ReactiveCommand的按鈕用於將更多項目加載到ReactiveList中時被禁用。
第二次打開查看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;
}
}
}
我得到了要顯示的初始測試條目。原因是因爲ResetPage()清除了最初的測試條目。 – kmc059000 2015-02-07 16:03:22
我想了很多這個。在ViewModel構造函數中放置調用非常重要!我將SearchText的'this.WhenAnyValue(...)'移到LoadItemsCommand設置之前。現在調用'LoadItemsCommand.Execute(null);' 然後我從後面的視圖代碼中的'OnAppearing()'中取出'LoadItemsCommand.Execute(null);'。但是,我仍然在第一次查看該頁面時出現問題,沒有任何內容出現。 – kmc059000 2015-02-07 16:15:10