我正在开发一个应用程序与Xamarin。窗体,试图利用ReactiveUI,但Xamarin。Forms ListView的行为不符合预期。
测试设置是一个输入字段,我在其中输入值。我订阅了ReactiveList上的更改,并将值添加到ListView中。
问题:ListView更新了几秒钟,然后就停止了。
示例代码:
<!-- 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>
ViewModel + SearchResult类:
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; }
}
这似乎是在GC期间错误地收集WeakReferences的错误。我没有足够的知识来做调试,但是其他一些聪明的人做了:
https://github.com/reactiveui/ReactiveUI/issues/806https://bugzilla.xamarin.com/show_bug.cgi?id=31415(打开xamarin bug报告)
处理:
将这个类添加到您的项目中:
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));
}
}
并使用它来代替ReactiveList:
public class ViewModel : ReactiveObject {
public ReactiveObservableCollection<SearchResult> SearchResults { set; get; }
public ViewModel()
{
// use ReactiveObservableCollection instead of ReactiveList
this.SearchResults = new ReactiveObservableCollection<SearchResult>()
{
ChangeTrackingEnabled = true
};
}
另外,确保在集合上使用.ObservableCollection属性作为ItemSource(而不仅仅是集合)!
this.ResultView.ItemsSource = viewModel.SearchResults.ObservableCollection;
不是 this.ResultView.ItemsSource = viewModel.SearchResults;
这应该能解决问题。
HTH !