Pageable поиск в реальном времени с ReactiveUI - PullRequest
1 голос
/ 17 октября 2019

У меня есть интерфейс, который я добавляю в свою ViewModel, когда мне нужно, чтобы мой вид был отображаемым на странице

public interface IPageable
{
    Task LoadNextPage();
    bool IsLoadingPage { get; set; }
}

Затем я присоединяю PageableBehavior к своему ListView, и всякий раз, когда мой ListView достигает днастраницы, он вызывает IPageable.LoadNextPage(); в ViewModel. (примечание: у меня все это работает, когда я не использую ReactiveUI)

Моя проблема в том, что, хотя я могу легко реагировать на поисковые запросы, я не могу понять, как также загрузить следующую страницу вРеактивный путь в _searchResults.

public class SeedSelectionViewModel : ReactiveObject, IPageable
{
    private const int PageSize = 30;
    private const int Threshold = 3;
    private static readonly TimeSpan _throttle = TimeSpan.FromMilliseconds(200);
    private readonly ISeedInputDataService _dataService;
    private readonly ObservableAsPropertyHelper<IEnumerable<SeedVarietySeed>> _searchResults;

    public SeedSelectionViewModel(ISeedInputDataService dataService)
    {
        _dataService = dataService;

        this.WhenAnyValue(x => x.SearchText)
            .Throttle(_throttle)
            .Select(term => term?.Trim())
            .DistinctUntilChanged()
            .Where(term => !string.IsNullOrWhiteSpace(term) && term.Trim().Length >= Threshold)
            .SelectMany((searchText,count,token) => SearchSeedVarieties(searchText,0))
            .ObserveOn(RxApp.MainThreadScheduler)
            .ToProperty(this, nameof(SearchResults), out _searchResults);
    }

    [Reactive] public string SearchText { get; set; }

    [Reactive] public bool IsLoadingPage { get; set; }

    public IEnumerable<SeedVarietySeed> SearchResults => _searchResults.Value;

    private Task<IEnumerable<SeedVarietySeed>> SearchSeedVarieties(string searchText, int skip) 
        => _dataService.FindSeedVarieties(searchText, skip, PageSize, CancellationToken.None);

    public Task LoadNextPage()
    {
        // how do I load additional results into _searchResults?
        return Task.CompletedTask;
    }
}

1 Ответ

1 голос
/ 17 октября 2019

Проблема в том, что вы не можете использовать ObservableAsPropertyHelper таким образом. Вы не можете изменить его из двух разных подписок.

Правильный способ справиться с этим - использовать ObservableCollection<T> или аналогичный и вызывать InvokeCommand из WhenAnyValue

ctor()
{
    _loadDataCommand = ReactiveCommand.CreateFromTask<string>(LoadData);

    this.WhenAnyValue(x => x.SearchText)
            .Throttle(_throttle)
            .Select(term => term?.Trim())
            .DistinctUntilChanged()
            .Where(term => !string.IsNullOrWhiteSpace(term) && term.Trim().Length >= Threshold)
            .ObserveOn(RxApp.MainThreadScheduler)
            .InvokeCommand(_loadDataCommand);
}

private async Task LoadData(string searchText)
{
    var result = await _dataService.FindSeedVarieties(searchText, 0, PageSize, CancellationToken.None).ConfigureAwait(true);
    SearchResults.ReplaceRange(result);
}
...