2015-02-07 9 views
5

Mi sento come se lo stessi facendo nel modo giusto, ma non sono sicuro. Sto caricando oggetti in una ReactiveList nel mio ViewModel in modo asincrono. Attraverso Xamarin Forms, ho associato l'Elenco alla proprietà ItemSource di un ListView in Xamarin Forms. Ho anche una casella di ricerca che cancellerà la ReactiveList e aggiungerà nuovi elementi alla ReactiveList.Binding ReactiveList <T> a ListView in Xamarin Forms

La prima volta che apro la vista, nessuna interazione fa caricare la lista e un pulsante associato a un ReactiveCommand per caricare più elementi in ReactiveList è disabilitato.

La seconda volta che apro la ViewViewView esegue quasi immediatamente gli oggetti nel nuovo ViewModel, ma ancora, le interazioni non sembrano funzionare. Tuttavia, la modifica della casella di ricerca in realtà elimina gli elementi da ListView, ma gli elementi non vengono aggiunti.

Questo comportamento è su iOS. Sono ReactiveUI 6.3.1 e Xamarin Forms 1.3.2.6316.

qui è il problema semplificata:

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; } 


} 

mio 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> 

mio punto di vista code-behind:

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

Ho visualizzato la voce iniziale del test. Il motivo era perché ResetPage() stava cancellando quella voce di test iniziale. – kmc059000

+0

Ho capito molto di questo. Il posizionamento delle chiamate nel costruttore ViewModel è importante! Ho spostato il 'this.WhenAnyValue (...)' per il SearchText prima dell'impostazione di LoadItemsCommand. 'ResetPage()' ora chiama 'LoadItemsCommand.Execute (null);' E ho estratto 'LoadItemsCommand.Execute (null);' da 'OnAppearing()' nel codice di vista retrostante. Tuttavia sto ancora ricevendo il problema dove la prima volta che visualizzo la pagina, non appare nulla. – kmc059000

risposta

4

questo sembra essere un bug con entrambi Xamarin Forms o ReactiveUI. Il problema è documentato qui: https://github.com/reactiveui/ReactiveUI/issues/806

Ho cambiato il tipo di public ReactiveList<ItemViewModel> List in public ObservableCollection<ItemViewModel> List che ha risolto il problema.

+0

Sono molto sorpreso da questo problema, ReactiveUI mi ha impressionato per la sua stabilità negli ultimi 2-3 anni. – Felix

0

Your ItemViewModel è un oggetto Reactive, tuttavia, non è stato codificato correttamente il setter. Ricorda, dovresti usare this.RaiseAndSetIfChanged nel setter per aumentare NPC.

+0

Non richiesto per una proprietà ReactiveList <>, a meno che non si desideri sovrascrivere l'originale. – kenny

+0

Non sai perché non è necessario se ovviamente questo non ha funzionato? –

Problemi correlati