1

我在基于以下(旧版)示例的 WPF MVVM 应用程序中实现了 ReactiveUI 异步搜索例程:

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;
        }
    }
} 

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}" />
4

1 回答 1

1

在您的视图模型中,不要让 Matches 实例创建类型为SearchResultMySearchResult 的属性。还要在 SearchResult 上实现 INotifyPropertyChanged。每次搜索操作后更新 SearchResult

现在您的列表框绑定将像<ListBox Grid.Row="1" Margin="6" ItemsSource="{Binding MySearchResult.Matches}" />

要显示搜索结果,您可以使用如下文本块:

 <TextBlock>
    <TextBlock.Text>
        <MultiBinding StringFormat="Found {0} matches in {1}s">
            <Binding Path="MySearchResult.MatchCount"/>
             <Binding Path="MySearchResult.SearchTime"/>
        </MultiBinding>
    </TextBlock.Text>
</TextBlock>
于 2013-09-10T17:13:38.487 回答