我一直在使用绑定到列表视图的Collection View Source对象,而CVS是Observable对象集合之上的视图。
我知道如何使用以下技术应用过滤器:
cvs.Filter += new FilterEventHandler(SomeFilterFunction);
当您只在一个函数中过滤时,这可以正常工作。问题是我想要在已经过滤的CVS之上进行过滤。如果我有另一个函数根据不同的条件过滤视图中的对象,则仅根据第二个过滤器中的条件过滤对象,并且第一个过滤器的结果消失。
以下是一些解释我问题的示例代码:
cvs.Filter += new FilterEventHandler(SomeFilterFunction1);
cvs.Filter += new FilterEventHandler(SomeFilterFunction2);
public void SomeFilterFunction1(object sender, FilterEventArgs e)
{
SomeObject example = e.Item as SomeObject;
if(example.Name.Contains("A"))
{
e.Accepted = true;
}
else
{
e.Accepted = false;
}
}
public void SomeFilterFunction2(object sender, FilterEventArgs e)
{
SomeObject example = e.Item as SomeObject;
if(example.Name.Contains("B"))
{
e.Accepted = true;
}
else
{
e.Accepted = false;
}
}
所以在这个例子中,我只想要过滤器接受字母A和B的“SomeObjects”。我的问题是,当使用filterfunction2进行调用cvs + = Filter时,只接受包含字母B的对象名称,忽略带有字母A的对象。因此,当它们不应该被接受时,接受包含字母B而不是A的对象名称。
我目前解决这个问题的方法是创建一个“Master”过滤器函数,其中包含每个过滤器函数,并且我通过每个过滤器运行每个Object,如果对象通过所有过滤器,则接受它。这确实有效,但我的代码现在变得疯狂,逻辑失控。有谁知道如何对CVS的最后一个过滤器的结果应用新的过滤函数?为什么CVS不会自动执行此操作而不是通过每个过滤器发送每个Object,或者我没有以正确的方式考虑CVS?
答案 0 :(得分:1)
问题是应用多个过滤器事件处理程序,是否所有处理程序都被调用,而CollectionViewSource
未考虑e.Accepted
的单个结果。结果将始终是最后一个事件处理程序中e.Accepted
的值。
我创建了一个管理器类,允许处理多个FilterEventHandler
函数,并使用AND或OR逻辑处理它们的结果。因此,要么所有过滤器都为true,要么至少有一个过滤器结果为true。
public class MultipleFilterHandler
{
private readonly CollectionViewSource collection;
public MultipleFilterLogic Operation {get; set; }
public MultipleFilterHandler(CollectionViewSource collection, MultipleFilterLogic operation)
{
this.collection = collection;
this.Operation = operation;
}
public MultipleFilterHandler(CollectionViewSource collection) :
this( collection, MultipleFilterLogic.Or)
{
}
private event FilterEventHandler _filter;
public event FilterEventHandler Filter
{
add
{
_filter += value;
collection.Filter -= new FilterEventHandler(CollectionViewFilter);
collection.Filter += new FilterEventHandler(CollectionViewFilter);
}
remove
{
_filter -= value;
collection.Filter -= new FilterEventHandler(CollectionViewFilter);
collection.Filter += new FilterEventHandler(CollectionViewFilter);
}
}
private void CollectionViewFilter(object sender, FilterEventArgs e)
{
if (_filter == null)
return;
foreach (FilterEventHandler invocation in _filter.GetInvocationList())
{
invocation(sender, e);
if ((Operation == MultipleFilterLogic.And && !e.Accepted) || (Operation == MultipleFilterLogic.Or && e.Accepted))
return;
}
}
}
public enum MultipleFilterLogic
{
And,
Or
}
只需根据需要在MultipleFilterHandler的Filter属性上添加和删除事件处理程序,它将管理CollectionViewSource的连接。
答案 1 :(得分:1)
你可以这样做:
cvs.Filter += new FilterEventHandler(SomeFilterFunction1);
cvs.Filter += new FilterEventHandler(SomeFilterFunction2);
public void SomeFilterFunction1(object sender, FilterEventArgs e)
{
SomeObject example = e.Item as SomeObject;
e.Accepted &= example.Name.Contains("A");
//if you prefer OR logic use this one:
//e.Accepted |= example.Name.Contains("A");
}
public void SomeFilterFunction2(object sender, FilterEventArgs e)
{
SomeObject example = e.Item as SomeObject;
e.Accepted &= example.Name.Contains("B");
//if you prefer OR logic use this one:
//e.Accepted |= example.Name.Contains("B");
}
这样做的是do和AND(如果使用| =运算符,则为OR)和Accepted属性中的当前值,使得过滤器协同工作。
编辑:这是在.NET 4.5中制作的