WPF隐藏重复与CollectionViewSource
本文关键字:CollectionViewSource 隐藏 WPF | 更新日期: 2023-09-27 18:02:37
我有一个ObservableCollection<M> fooBar {get;set;}
。类M.cs
看起来像这样:
public class M{
private int _ID;
public int ID {
get {return this._ID;}
set {this._ID = value;}
}
private string _number;
public int Number {
get {return this._number;}
set {this._number = value;}
}
private string _power;
public int Power {
get {return this._power;}
set {this._power = value;}
}
/*
...
*/
}
现在我只想隐藏属性Power
的重复项。在我的.xaml
代码中,我这样写:
<UserControl.Resources>
<CollectionViewSource x:Key="myCollection" Source="{Binding Path=fooBar}">
<CollectionViewSource.GroupDescriptions>
<PropertyGroupDescription PropertyName="Power"/>
</CollectionViewSource.GroupDescriptions>
</CollectionViewSource>
</UserControl.Resources>
我将这个集合绑定到我的ComboBox
。
<ComboBox Name="cbValues"
ItemsSource="{Binding Source={StaticResource myCollection}}"
DisplayMemberPath="{Binding Power}"
SelectedValuePath="{Binding Power}"
/>
ComboBox
填充了正确的值,但仍然存在重复。我怎样才能把它们藏起来?
你可以试试CollectionViewSource.Filter
myCollection.Filter+= new FilterEventHandler(ShowOnlyDistinctFilter);
此事件处理程序用于筛选和显示与数据源相关的数据
private void ShowOnlyDistinctFilter(object sender, FilterEventArgs e)
{
var item= e.Item as M;
if (item != null)
{
//Your distinct logic here
}
}
我也有这个问题,但找不到一个好的答案,所以这里是我想到的通用解决方案。
可以很好地与多个CollectionViewSource一起工作,至少在我的情况下,每个CollectionViewSource需要在不同的对象上是不同的。
这是泛型方法:
您只需要确保T是与CollectionViewSource.Source相同的类型。
private void cvs_filter_distinct<T>(CollectionViewSource sender, FilterEventArgs e, Func<T, T, bool> arg)
{
if (e.Item != null)
{
switch (sender.View.IsEmpty)
{
case true:
e.Accepted = true;
break;
default:
switch ((sender.View.Cast<T>()).All(x => arg(x, (T)e.Item)))
{
case true:
e.Accepted = true;
break;
default:
e.Accepted = false;
break;
}
break;
}
}
}
示例:给定如下对象:
public class My_Class
{
public string String_A { get; set; }
public string String_B { get; set; }
}
使用数据集合和CollectionViewSource,如:
public ObservableCollection<My_Class> My_Data_Collection = new ObservableCollection<My_Class>();
public CollectionViewSource My_CollectionViewSource = new CollectionViewSource();
我们添加了通用过滤器,并且"curry"Function via lambda:
public void Some_Methood()
{
My_CollectionViewSource.Source = My_Data_Collection;
My_CollectionViewSource.Filter +=
new FilterEventHandler(
(sender, e) => cvs_filter_distinct<My_Class>(
sender:(CollectionViewSource)sender,
e: e,
arg: (a, b) => a.String_A != b.String_A));
}
对我来说这很好,因为我可以指定要比较的对象以及如何比较它们。此外,我不必为每个CollectionViewSource编写单独的筛选方法。
如果你想更花哨,你可以扩展它来过滤基于项目在另一个集合,像这样:
private void cvs_filter_distinct<T, O>(CollectionViewSource sender, FilterEventArgs e, Func<T, O, bool> arg, O[] otherCollection)
{
T[] _view_values;
if (e.Item != null)
{
switch (sender.View.IsEmpty)
{
case true:
e.Accepted = true;
break;
default:
_view_values =
sender
.View
.Cast<T>()
.ToArray();
e.Accepted =
otherCollection
.All(a => _view_values
.All(a2 => arg(a2, a)));
break;
}
}
}
private class My_Other_Class
{
public string Another_String { get; set; }
}
public void Some_Other_Methood()
{
My_Other_Class[] my_other_data_collection = new My_Other_Class[] {
new My_Other_Class() {
Another_String = "some other text" } };
My_CollectionViewSource.Source = My_Data_Collection;
My_CollectionViewSource.Filter +=
new FilterEventHandler(
(sender, e) => cvs_filter_distinct<My_Class,My_Other_Class>(
sender: (CollectionViewSource)sender,
e: e,
arg: (a, b) => a.String_A != b.Another_String,
otherCollection: my_other_data_collection));
}