1

我在实现一项功能时遇到了一些性能问题,其中列表框是实时过滤的,而用户正在将过滤器字符串键入文本框。我正在尝试创建的功能类似于 WP7 中的通话记录搜索。

我创建了一个简单的项目来测试它并复制粘贴下面的重要部分。基本上我有一个文本框,用户应该在其中编写一个字符串,用于过滤绑定到列表框的数据。这种过滤应该实时发生,而不是在点击任何类型的过滤按钮等之后。

ListBox 绑定到使用 ObservableCollection 作为源的 CollectionViewSource。当在文本框中输入内容时,该值会立即数据绑定到视图模型中的属性。View 模型属性的 setter 会触发 CollectionViewSource 的过滤,从而更新 ListBox 的内容。

在我正在做的实际项目中,ListBox 可以包含一百左右的项目。

这是相关的 XAML:

        <TextBox TextChanged="TextBox_TextChanged" Text="{Binding FilterString, Mode=TwoWay, UpdateSourceTrigger=Explicit}"></TextBox>

        <ListBox ItemsSource="{Binding ItemsListCVS.View, Mode=TwoWay}">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding Prop1, Mode=TwoWay}"></TextBlock>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>

触发即时绑定到 ViewModel 属性的代码:

    private void TextBox_TextChanged(object sender, System.Windows.Controls.TextChangedEventArgs e)
    {
        var textBox = sender as TextBox;
        // Update the binding source
        BindingExpression bindingExpr = textBox.GetBindingExpression(TextBox.TextProperty);
        bindingExpr.UpdateSource();
    }

视图模型:

    private ObservableCollection<AnItem> _itemsList = new ObservableCollection<AnItem>();
    private CollectionViewSource _itemsListCvs = new CollectionViewSource();


    public ObservableCollection<AnItem> ItemsList
    {
        get
        {
            return _itemsList;
        }

        set
        {         
            _itemsList = value;

            // Update bindings, no broadcast
            RaisePropertyChanged(ItemsListPropertyName);
        }
    }

    public string FilterString
    {
        get
        {
            return _filterString;
        }

        set
        {
            if (_filterString == value)
            {
                return;
            }

            _filterString = value;

            // Update bindings, no broadcast
            RaisePropertyChanged(FilterStringPropertyName);

            this.Filter();
        }
    }
    public CollectionViewSource ItemsListCVS
    {
        get
        {
            return _itemsListCvs;
        }

        set
        {
            if (_itemsListCvs == value)
            {
                return;
            }

            _itemsListCvs = value;

            // Update bindings, no broadcast
            RaisePropertyChanged(ItemListPropertyName);
        }
    }

    public MainViewModel()
    {
        var items = Builder<AnItem>.CreateListOfSize(100).Build();
        this.ItemsList = new ObservableCollection<AnItem>(items);
        this.ItemsListCVS.Source = this.ItemsList;
    }

    private void Filter()
    {
        this.ItemsListCVS.View.Filter = r =>
        {
            if (r == null) return true;
            return ((AnItem)r).Prop1.ToString().ToLowerInvariant().Contains(FilterString);
        };            
    }

数据绑定到列表的项目类:

public class AnItem
{
    public string Prop1 { get; set; }
    public string Prop2 { get; set; }
    public string Prop3 { get; set; }
    public string Prop4 { get; set; }
    public string Prop5 { get; set; }
}

问题:

一切正常,但是在写入 TextBox 和更新 ListBox 之间有一个可怕的延迟。

我只是做错了吗?如果是这样,那么我应该如何改变我的方法?我认为这是很常见的要求,因此可能有一些不错的解决方案。

4

1 回答 1

1

您可以使用工具包中的 AutoCompleteBox 而不是滚动您自己的过滤器吗?

作为替代方案,您能否对数据进行分类并通过 LongListSelector 使其可搜索?

最终,如果您的代码性能不佳,您应该使用 Profiler 来查看实际瓶颈在哪里。http://msdn.microsoft.com/en-us/library/hh202934(v=vs.92).aspx

于 2011-09-12T13:42:31.560 回答