2016-06-30 15 views
0

ich eine App mit Xamarin.Forms entwickle, versuchen ReactiveUI zu nutzen, aber Xamarin.Forms Listview verhält sich nicht wie erwartet.Listview stoppt nach wenigen Sekunden aktualisiert, wenn ich ein Listview binden an ReactiveList

Die Testkonfiguration ist ein Eingabefeld, in das ich Werte eingeben kann. Ich abonniere Änderungen in der ReactiveList und füge den Wert einer ListView hinzu.

Das Problem: Das Listview-Updates für ein paar Sekunden und stoppt dann nur. Konsole protokolliert weiterhin Eingaben.

Beispielcode unten:

<!-- xaml layouts omitted for brevity -->   
     <Entry x:Name="searchbox" HorizontalOptions="FillAndExpand" 
      Text="{Binding SearchQuery, Mode=TwoWay}" 
     /> 
     <ListView x:Name="ResultView"> 
     <ListView.ItemTemplate> 
      <DataTemplate> 
      <TextCell Text="{Binding Address}"></TextCell> 
      </DataTemplate> 
     </ListView.ItemTemplate> 
     </ListView> 

Ansichtsmodell + Search Klasse:

public class SearchViewModel : ReactiveObject 
{ 
    public ReactiveList<SearchResult> SearchResults { get; set; } 

    private string searchQuery; 
    public string SearchQuery 
    { 
     get { return searchQuery; } 
     set { this.RaiseAndSetIfChanged(ref searchQuery, value); } 
    } 

    public ReactiveCommand<List<SearchResult>> Search { get; set; } 


    public SearchViewModel() 
    { 
     // Set up our ListView data list 
     this.SearchResults = new ReactiveList<SearchResult>(); 
     this.SearchResults.ChangeTrackingEnabled = true; 

     Search = ReactiveCommand.CreateAsyncTask(async _ => { 
      return await GenerateSearchResultAsync(this.SearchQuery); 
     }); 

     Search.Subscribe(results => { 
      SearchResults.Clear(); // just replace output every time 
      SearchResults.AddRange(results); 

      // output results to console 
      results.ForEach(r => Console.WriteLine(r.Address)); 
     }); 

     // this used to contain a condition I removed for brevity 
     this.WhenAnyValue(x => x.SearchQuery).InvokeCommand(this, x => x.Search); 
    } 

    // create a new result list and return it, async code removed for demo-simplicity 
    private static async Task<List<SearchResult>> GenerateSearchResultAsync(string value) 
    { 
     var rv = new List<SearchResult>(); 
     rv.Add(new SearchResult(value + " " + DateTime.Now.ToString("hh:mm:ss.FFFF")));    
     return rv; 
    } 

} 

public class SearchResult 
{ 
    private string address; 
    public SearchResult(string s) 
    { 
     this.Address = s; 
    } 
    public string Address { get; set; } 
} 

Antwort

1

Dies scheint ein Fehler zu sein, wenn WeakReferences versehentlich während GC gesammelt werden. Ich bin nicht so kenntnisreich das Debuggen zu tun, aber einige andere intelligente Jungs haben:

https://github.com/reactiveui/ReactiveUI/issues/806

https://bugzilla.xamarin.com/show_bug.cgi?id=31415 (offen Xamarin Bug-Report)

Umgehung:

diese Klasse hinzufügen zu Ihrem Projekt:

public class ReactiveObservableCollection<T> : ReactiveList<T> 
{ 
    public ObservableCollection<T> ObservableCollection { private set; get; } 

    public ReactiveObservableCollection() 
    { 
     this.ObservableCollection = new ObservableCollection<T>(); 
     ItemsAdded.Subscribe(ObservableCollection.Add); 
     ItemsRemoved.Subscribe((x) => ObservableCollection.Remove(x)); 
    } 
} 

an d es anstelle des ReactiveList verwenden:

public class ViewModel : ReactiveObject { 

public ReactiveObservableCollection<SearchResult> SearchResults { set; get; } 

public ViewModel() 
{ 
    // use ReactiveObservableCollection instead of ReactiveList 
    this.SearchResults = new ReactiveObservableCollection<SearchResult>() 
    { 
     ChangeTrackingEnabled = true 
    }; 
} 

Stellen Sie außerdem sicher, dass die .ObservableCollection Eigentum an der Sammlung als ItemSource zu verwenden (statt nur die Sammlung)!

this.ResultView.ItemsSource = viewModel.SearchResults.ObservableCollection; 

anstelle von

this.ResultView.ItemsSource = viewModel.SearchResults;

Dies sollte das Problem lösen.

HTH!