Логика фильтрации CollectionViewSource
Дизайн, который я придумал для фильтрации, в лучшем случае неудобен, а в худшем - глючит. Идея состоит в том, чтобы иметь базовый класс для поддержки списка выбора и позволить подклассам добавлять дополнительную логику фильтрации по мере необходимости.
Что меня особенно смущает, так это то, как запускать представление для фильтрации при изменении различных критериев фильтрации (см. _ApplyFiler() ниже). Правильно ли настроен фильтр? Где я должен отписаться / установить его на нуль после того, как он фильтрует?
Ура, Беррил
некрасивый код:
public class SubjectPickerBase<T> : ViewModelBase, ISubjectPicker<T>
where T : class, IAvailableItem, INotifyPropertyChanged, IActivitySubject
{
public CollectionViewSource Subjects { get; private set; }
protected SubjectPickerBase() { }
protected void _Initialize(IEnumerable<T> subjects, string subjectName) {
...
Subjects = new CollectionViewSource { Source = subjects };
_ApplyFilter();
}
protected void _ApplyFilter() {
Subjects.View.Filter += Filter;
}
private bool Filter(object obj)
{
var subject = obj as T;
if (ReferenceEquals(subject, null)) return false;
NotifyPropertyChanged(() => Status);
var isIncludedBySubclass = OnFilter(subject);
var isIncludedByBase = subject.IsAvailable;
return isIncludedByBase & isIncludedBySubclass;
}
/// <summary>Hook to allow implementing subclass to provide it's own filter logic</summary>
protected virtual bool OnFilter(T subject) { return true; }
}
public class ProjectSelectionViewModel : SubjectPickerBase<ProjectViewModel>
{
public ProjectSelectionViewModel(IEnumerable<ProjectViewModel> projects)
{
...
_Initialize(projects, Strings.ActivitySubject__Project);
}
public string DescriptionMatchText {
get { return _descriptionMatchText; }
set {
ApplyPropertyChange<ProjectSelectionViewModel, string>(ref _descriptionMatchText, x => x.DescriptionMatchText, value);
_ApplyFilter();
}
}
private string _descriptionMatchText;
protected override bool OnFilter(ProjectViewModel subject)
{
...
var isDescriptionMatch = subject.IsMatch_Description(DescriptionMatchText);
return isPrefixMatch && isMidfixMatch && isSequenceNumberMatch && isDescriptionMatch;
}
}
1 ответ
Есть несколько частей для нетривиальной манипуляции представлением, которое я пропустил, все они имеют отношение к обновлению CollectionView, которое является свойством CollectionViewSource:
Первая часть моего вопроса была, когда установить фильтр. Для моего случая использования лучше всего оказалось зарегистрироваться для события CollectionViewSource. Filter, а затем использовать метод View.Refresh при каждом изменении фильтра. Первоначальная регистрация события фильтра также запускает обработчик событий, и многие из примеров msdn, которые вы видите, показывают это как способ фильтрации представления и ничего более. Но если ваш сценарий не является тривиальным, и пользователь может изменить некоторые критерии фильтрации, вам нужно использовать один или несколько из перечисленных выше методов и свойств, связанных с обновлением.
Вторая часть моего вопроса была связана с тем, нужно ли вам отказаться от подписки на событие фильтра, и если да, то когда. Что ж, получается, что вам не нужно отписываться, но если вы это сделаете, это эффективно очищает любую фильтрацию представления. И многие из тривиальных примеров msdn делают именно это, чтобы очистить фильтр, что, безусловно, нужно, если вы хотите полностью очистить фильтрацию, но для моего случая использования это было не то, что я действительно хотел. Я хотел очистить некоторые критерии, но не другие, и снова использование Refresh (в нужное время) дало мне желаемое поведение.
НТН,
Berryl