【问题标题】:Multiple bindings from ReactiveUI search using ObservableAsPropertyHelper<>使用 ObservableAsPropertyHelper<> 来自 ReactiveUI 搜索的多个绑定
【发布时间】:2023-03-23 19:29:01
【问题描述】:

我根据以下(旧版)示例在 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&lt;string&gt;,它将绑定到同一个 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}" />

【问题讨论】:

    标签: c# wpf mvvm system.reactive reactiveui


    【解决方案1】:

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

    现在您的列表框绑定将类似于&lt;ListBox Grid.Row="1" Margin="6" ItemsSource="{Binding MySearchResult.Matches}" /&gt;

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

     <TextBlock>
        <TextBlock.Text>
            <MultiBinding StringFormat="Found {0} matches in {1}s">
                <Binding Path="MySearchResult.MatchCount"/>
                 <Binding Path="MySearchResult.SearchTime"/>
            </MultiBinding>
        </TextBlock.Text>
    </TextBlock>
    

    【讨论】:

    • 谢谢!为了与 ReactiveUI 风格保持一致,我使用了 ObservableAsPropertyHelper。我的编辑反映了有效的解决方案。
    猜你喜欢
    • 2013-05-16
    • 2014-02-16
    • 2015-03-28
    • 2017-06-18
    • 1970-01-01
    • 2019-09-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多