次の(レガシー)例に基づいて、WPF MVVMアプリケーション内にReactiveUI非同期検索ルーチンの実用的な実装があります。
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;
}
}
}
ReactiveXAML は期待どおりに機能しており、Matches プロパティに簡単にバインドできます。
<ListBox Grid.Row="1" Margin="6" ItemsSource="{Binding Matches}" />
ただし、次のようなより複雑な結果構造を返すように TheSearchService.DoSearchAsync() をリファクタリングしたいと思います。
public class SearchResult
{
public string Query { get; set; }
public List<string> Matches { get; set; }
public int MatchCount { get; set; }
public double SearchTime { get; set; }
}
一致は引き続き として表されList<string>
、同じ ListBox にバインドされますが、次のような形式で一致数と検索時間を返す各検索の文字列メタデータ プロパティにもバインドしたいと思います。
string.Format("Found {0} matches in {1}s", x.MatchCount, x.SearchTime)
ViewModel の実装を変更して、検索ごとに複数のバインドを許可するにはどうすればよいですか?
受け入れられた回答に基づく実用的な実装
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;
}
}
}
これがビューです
<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}" />