我在实现一项功能时遇到了一些性能问题,其中列表框是实时过滤的,而用户正在将过滤器字符串键入文本框。我正在尝试创建的功能类似于 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 之间有一个可怕的延迟。
我只是做错了吗?如果是这样,那么我应该如何改变我的方法?我认为这是很常见的要求,因此可能有一些不错的解决方案。