I have a working implementation of a ReactiveUI asynchronous search routine within an WPF MVVM application based off of the following (legacy) example:
http://blog.paulbetts.org/index.php/2010/07/05/reactivexaml-series-implementing-search-with-observableaspropertyhelper/
public class TheViewModel : ReactiveObject
{
private string query;
private readonly ObservableAsPropertyHelper<List<string>> matches;
public TheViewModel()
{
var searchEngine = this.ObservableForProperty(input => input.Query)
.Value()
.DistinctUntilChanged()
.Throttle(TimeSpan.FromMilliseconds(800))
.Where(query => !string.IsNullOrWhiteSpace(query) && query.Length > 1);
var search = searchEngine.SelectMany(TheSearchService.DoSearchAsync);
var latestResults =
searchEngine.CombineLatest(search, (latestQuery, latestSearch) => latestSearch.Query != latestQuery ? null : latestSearch.Matches)
.Where(result => result != null);
matches = latestResults.ToProperty(this, result => result.Matches);
}
public string Query
{
get
{
return query;
}
set
{
this.RaiseAndSetIfChanged(ref query, value);
}
}
public List<string> Matches
{
get
{
return matches.Value;
}
}
}
The ReactiveXAML is working as expected and I can easily bind to the Matches property like so
<ListBox Grid.Row="1" Margin="6" ItemsSource="{Binding Matches}" />
However I would like to refactor TheSearchService.DoSearchAsync() to return a more complex result structure sort of like this:
public class SearchResult
{
public string Query { get; set; }
public List<string> Matches { get; set; }
public int MatchCount { get; set; }
public double SearchTime { get; set; }
}
The matches would still be represented as a List<string>
which would be bound to the same ListBox but I'd like also like to bind to a string metadata property on each search that returns the match count and search time in some sort of format such as:
string.Format("Found {0} matches in {1}s", x.MatchCount, x.SearchTime)
How could I change the ViewModel implementation to allow multiple bindings for each search?
Working implementation based on accepted answer
public class TheViewModel : ReactiveObject
{
...
private readonly ObservableAsPropertyHelper<SearchResult> results;
public TheViewModel()
{
...
var latestResults = searchEngine.CombineLatest(search, (latestQuery, latestSearch) => latestSearch.Query != latestQuery ? null : latestSearch)
.Where(result => result != null);
results = latestResults.ToProperty(this, result => result.Result);
}
...
public SearchResult Result
{
get
{
return results.Value;
}
}
}
Here is the view
<StackPanel>
<TextBox Text="{Binding Query, UpdateSourceTrigger=PropertyChanged}"
Margin="6"
FontSize="26" />
<TextBlock>
<TextBlock.Text>
<MultiBinding StringFormat="Found {0} matches in {1}s">
<Binding Path="Result.MatchCount" />
<Binding Path="Result.SearchTime" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</StackPanel>
<ListBox Grid.Row="1"
Margin="6"
ItemsSource="{Binding Result.Matches}" />