У меня есть некоторые проблемы с производительностью при реализации функции, когда список фильтруется в реальном времени, пока пользователь вводит строку фильтра в текстовое поле. Функция, которую я пытаюсь создать, похожа на поиск по истории вызовов в WP7.
Я создал простой проект для проверки этого и скопировал важные биты ниже. В основном у меня есть TextBox, где пользователь должен написать строку, которая будет использоваться для фильтрации данных, связанных со списком. Эта фильтрация должна выполняться в режиме реального времени, а не после нажатия какой-либо кнопки фильтра и т. Д.
ListBox привязан к CollectionViewSource, который использует ObservableCollection в качестве источника. Когда что-то вводится в текстовое поле, это значение мгновенно привязывается к свойству в модели представления. Установщик свойства View Model запускает фильтрацию 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();
}
ViewModel:
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);
};
}
AnItem-класс, привязанный к списку данных:
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 существует огромная задержка.
Я просто делаю это неправильно? Если так, то как мне изменить свой подход? Я думаю, что это довольно распространенное требование, поэтому, вероятно, есть хорошее решение для него.