[英]Filter Multiple Columns ListView C# WPF
我想使用多列和多过滤器进行过滤以过滤我的ListView,但是我不知道如何...
这是我的想法:一个窗口显示当前选定的列标题,您可以在其中选择下拉列表中的=或>然后使用您的条件进行过滤,我只找到一列的解决方案,但对多重过滤器一无所知...
数据加载:
var xdoc = XDocument.Load(@"C:\temp\webTsl.xml");
var units = from u in xdoc.Descendants("sl")
select new
{
EQNr = (string)u.Element("id"),
//EQCore = (string)u.Element(""),
ArtNr = (string)u.Element("artNr"),
Bez = (string)u.Element("bez"),
//KundenBez = (string)u.Element(""),
//ProjektNr = (string)u.Element(""),
//LiefDat = (DateTime)u.Element(""),
//EqStart = (DateTime)u.Element(""),
//GewaehrStart = (DateTime)u.Element(""),
//GewaehrEnde = (DateTime)u.Element("")
};
foreach (var unit in units)
{
items.Add(new Anlagen(unit.EQNr, unit.ArtNr, unit.Bez));
}
ListViewAnlagen.ItemsSource = CollectionViewSource.GetDefaultView(items);
类:
public virtual string EQNr { get; set; }
//public virtual string EQCore { get; set; }
public virtual string ArtNr { get; set; }
public virtual string Bez { get; set; }
//public virtual string KundenBez { get; set; }
//public virtual string ProjektNr { get; set; }
//public virtual DateTime? LiefDat { get; set; }
//public virtual DateTime? EqStart { get; set; }
//public virtual DateTime? GewaehrStart { get; set; }
//public virtual DateTime? GewaehrEnde { get; set; }
public Anlagen(string eqNr,string artNr, string bez) /*, DateTime liefdat, DateTime inbetnahme,DateTime garantiestart,DateTime garantieende*/
{
this.EQNr = eqNr;
//this.EQCore = eqCore;
this.ArtNr = artNr;
this.Bez = bez;
//this.KundenBez = kundenBez;
//this.ProjektNr = projektNr;
//this.LiefDat = liefDat;
//this.EqStart = eqStart;
//this.GewaehrStart = gewaehrStart;
//this.GewaehrEnde = gewaehrEnde;
}
public Anlagen()
{
}
基本上,您需要一个过滤器定义,在其中传递您的项目,并且特定于列的过滤器函数确定该项目是否满足过滤器。
假设您有一个过滤器界面,如下所示:
public interface IFilterBase<TItem>
{
PropertyInfo Property { get; } // can be used to display the property name etc.
bool ApplyFilter(T value);
}
和一些实现
public class StringContainsFilter<TItem> : IFilterBase<TItem>
{
public StringContainsFilter(PropertyInfo prop)
{
// TODO Requirements to check:
// typeof(TItem).IsAssignableFrom(prop.DeclaringType)
// typeof(string).IsAssignableFrom(prop.PropertyType)
}
// TODO Property getter implementation
public string ContainedText { get; set; } // TODO INotifyPropertyChanged
public bool ApplyFilter(TItem value)
{
// get the property value via reflection and check against the contains filter condition
var text = Property.GetValue(value) as string ?? "";
return text.Contains(ContainedText ?? "");
}
}
当然,您必须为过滤中实际要支持的所有内容(属性类型和操作)定义过滤器实现。
因此,基本上,对于每一列,您都可以通过属性类型来决定支持的过滤器,然后让用户选择过滤器并输入条件。
剩下的问题是如何应用一系列过滤器...假设用户输入了一些过滤器,并将每个过滤器保存在一个集合中,例如:
ObservableCollection<IFilterBase<TItem>> Filters;
然后,完整的项目集合可以变成一个过滤的项目集合,例如:
source.Where(item => Filters.All(filter => filter.ApplyFilter(item)))
为了使MVVM准备好过滤的项目集合,我在一个项目中使用了以下帮助器类:
public class ObservableLinq<TIn, TOut> : IEnumerable<TOut>, INotifyCollectionChanged
{
private ObservableCollection<TIn> _Source;
private Func<IEnumerable<TIn>, IEnumerable<TOut>> _Transformation;
public ObservableLinq(ObservableCollection<TIn> source, Func<IEnumerable<TIn>, IEnumerable<TOut>> transformation)
{
_Source = source;
_Transformation = transformation;
_Source.CollectionChanged += Source_CollectionChanged;
}
public ObservableLinq(IEnumerable<TIn> source, Func<IEnumerable<TIn>, IEnumerable<TOut>> transformation)
: this(source as ObservableCollection<TIn> ?? new ObservableCollection<TIn>(source), transformation)
{
}
private void Source_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
RaiseCollectionChanged();
}
public IEnumerator<TOut> GetEnumerator()
{
return _Transformation(_Source).GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
// could be a property as well, but this empathizes, that the source collection is not the primary functionality here
public ObservableCollection<TIn> GetSourceCollection()
{
return _Source;
}
public event NotifyCollectionChangedEventHandler CollectionChanged;
protected void RaiseCollectionChanged()
{
var handler = CollectionChanged;
if (handler != null)
{
// always reset as it would be pretty complicated to track the actual changes across all the linq thingies
handler(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
}
/// <summary>
/// Call when a filter relevant property changed on source collection entries
/// </summary>
public void CollectionChangedNeeded()
{
RaiseCollectionChanged();
}
}
用法:
public ObservableLinq<TItem, TItem> FilteredItems { get {...} set {...} }
// init:
FilteredItems = new ObservableLinq<TItem, TItem>(ItemsList, source.Where(item => Filters.All(filter => filter.ApplyFilter(item))));
然后,当item集合更改,item属性更改,活动的filter集合更改或filter属性更改时,触发已过滤项目的更新(当source集合为ObservableCollection
时,将注意项集合的更改)
FilteredItems.CollectionChangedNeeded();
与WPF提供的控件的内置筛选器功能相比,使用这种方法更灵活。 基于正则表达式的过滤器,用于自定义属性类型的过滤器,...在每种过滤器类型没有太多负担的情况下都可以实现。 只是过滤基础结构的初始设置并不是很简单。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.