我有ListView
我正在填充ObservableCollection
我正在根据TextBox
以下是我正在使用的代码的一部分:
private void Filter_TextChanged(object sender, TextChangedEventArgs e)
{
view = CollectionViewSource.GetDefaultView(Elementos_Lista.ItemsSource);
view.Filter = null;
view.Filter = new Predicate<object>(FilterList);
}
如果我想通过一个条件过滤列表,这没关系,但每当我想混合多个文本框进行过滤时,它总是根据ItemsSource进行过滤,而不是当前的结果集,这意味着有没有积累标准。
这是我的FilterList方法。
ItemDetail item = obj as ItemDetail;
if (item == null) return false;
string textFilter = txtFilter.Text;
if (textFilter.Trim().Length == 0) return true; //this returns the unfiltered results.
if ((item.problema.ToLower().Contains(textFilter.ToLower()))) return true;
return false;
有没有办法按多个条件过滤ObservableCollection(view),这些条件并不总是同时提供?。
我尝试更改FilterList方法以评估各种文本框,但我必须制作一个IF语句来检查匹配条件的所有可能性。
(filter1=value , filter2=value) OR
(filter1=value , filter2=empty) OR
(filter1=empty , filter2=value)
由于我打算使用至少5种不同的控件进行过滤,这根本不会很有趣。
示例:
List:
Maria, Age:26
Jesus, Age:15
Angela, Age:15
第一个过滤器
Filters:
Name: //Empty
Age: 15
Result:
Jesus, Age:15
Angela, Age:15
第二次过滤:
Filters:
Name: Jesus
Age: 15
Result:
Jesus, Age:15
我要做的是将过滤器应用于已经过滤的集合,而不是原始过滤集合,这种方法会用下一个过滤器覆盖应用的过滤器。
答案 0 :(得分:1)
好的,让我们看看,我周围有类似的东西......
[ContractClass(typeof(CollectionViewFilterContracts<>))]
public interface ICollectionViewFilter<in T> where T : class
{
bool FilterObject(T obj);
}
合同当然是可选的(CodeContracts)
[ContractClassFor(typeof(ICollectionViewFilter<>))]
public abstract class CollectionViewFilterContracts<T> : ICollectionViewFilter<T> where T : class
{
public bool FilterObject(T obj)
{
Contract.Requires<ArgumentNullException>(obj != null, "Filtered object can't be null");
return default(bool);
}
}
然后是基本实现,据我所知,你只使用字符串进行比较,所以这里只是字符串版本:
public abstract class CollectionFilterBase<T> : ICollectionViewFilter<T> where T : class
{
private readonly Dictionary<string, string> filters = new Dictionary<string, string>(10);
private readonly PropertyInfo[] properties;
protected CollectionFilterBase()
{
properties = typeof(T).GetProperties();
}
protected void AddFilter(string memberName, string value)
{
if (string.IsNullOrEmpty(value))
{
filters.Remove(memberName);
return;
}
filters[memberName] = value;
}
public virtual bool FilterObject(T objectToFilter)
{
foreach (var filterValue in filters)
{
var property = properties.SingleOrDefault(x => x.Name == filterValue.Key);
if(property == null)
return false;
var propertyValue = property.GetValue(objectToFilter, null);
var stringValue = propertyValue == null ? null : propertyValue.ToString(); // or use string.Empty instead of null, depends what you're going to do with it.
// Now you have the property value and you have your 'filter' value in filterValue.Value, do the check, return false if it's not what you're looking for.
//The filter will run through all selected (non-empty) filters and if all of them check out, it will return true.
}
return true;
}
}
现在一些有意义的实现,让我们说这是你的类,为简单起见:
public class Person
{
public string Name {get;set;}
public int Age {get;set;}
}
过滤器实现 - 同时 - 包含所有“过滤”控件的视图后面的视图模型,因此您可以相应地将文本框值绑定到属性。
public class PersonFilter : CollectionFilterBase<Person>
{
private string name;
public string Name
{
get
{
return name;
}
set
{
name = value;
//NotifyPropertyChanged somehow, I'm using Caliburn.Micro most of the times, so:
NotifyOfPropertyChange(() => Name);
AddFilter("Name", Name);
}
}
private int age;
public int Age
{
get
{
return age;
}
set
{
age = value;
//Same as above, notify
AddFilter("Age", Age.ToString()) // only a string filter...
}
}
}
然后在视图模型中有一个PersonFilter
对象实例。
ICollectionViewFilter<Person> personFilter = new PersonFilter();
然后你只需要在Filter
上使用CollectionView
事件来查看视图模型中的某些方法,例如:
CollectionView.Filter += FilterPeople
private void FilterPeople(object obj)
{
var person = obj as Person;
if(person == null)
return false;
return personFilter.FilterObject(person);
}
过滤器名称必须与过滤对象上的属性名称相同。 :)
当然你必须在某个地方调用CollectionView.Refresh();
,你可以将其移动到过滤器(例如,当属性发生变化时,你可以调用CollectionView.Refresh()
立即查看更改),你可以在事件处理程序中调用它,无论你想要什么。
这很简单,虽然性能可能会更好。除非您使用几十个过滤器过滤一公吨数据,否则调整和使用片段不会有太多问题。 :)