好吧,让我们看看,我这里也有类似的东西……
[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()
以立即查看更改),你可以在事件处理程序中调用它,但你想要。
这很简单,尽管性能可能会更好。除非您使用几十个过滤器过滤大量数据,否则在调整和使用代码段时应该不会有太多问题。:)