CollectionViewSource,如何过滤数据?
Posted
技术标签:
【中文标题】CollectionViewSource,如何过滤数据?【英文标题】:CollectionViewSource, how to filter data? 【发布时间】:2013-01-07 23:34:48 【问题描述】:我将 ComboBox 绑定到实体,但我希望过滤数据。
到目前为止,我已经尝试了两种方法:
“简单”一:通过t将过滤器直接应用到ObjectSet LINQ 到实体 设置过滤事件处理程序,如上所述 msdn我对第一种方法很满意,首先是因为生成到数据库的查询包含 WHERE 子句,因此不必从远程数据库中检索所有的全部数据....
但是,#2 方法要灵活得多,如果在运行时我想更改应用的过滤...我已按照 msdn 上的示例进行操作,但出现异常,为什么?
所以,我的问题是: 1. 哪种方法更好 2. 为什么会出现异常?
这是我的代码:
private void UserControl_Loaded(object sender, RoutedEventArgs e)
//Do not load your data at design time.
if (!System.ComponentModel.DesignerProperties.GetIsInDesignMode(this))
//Load your data here and assign the result to the CollectionViewSource.
System.Windows.Data.CollectionViewSource myCollectionViewSource =
(System.Windows.Data.CollectionViewSource)
this.Resources["tSCHEDEViewSource"];
// If I use this I get the data filtered on startup, but is it the right mode?
//myCollectionViewSource.Source = _context.TSCHEDE.Where(s => s.KLINEA == kLinea && s.FCANC == "T").OrderBy(s => s.DSCHEDA).OrderByDescending(s => s.DSTORICO);
// Instead If I apply my custom filtering logic
myCollectionViewSource.Filter += new FilterEventHandler(filterSource);
myCollectionViewSource.Source = _context.TSCHEDE; // ... Here i get an exception:
// 'System.Windows.Data.BindingListCollectionView' view does not support filtering. ???
private void filterSource(object sender, FilterEventArgs e)
TSCHEDE scheda = e.Item as TSCHEDE;
if (scheda != null)
if (scheda.KLINEA == 990)
e.Accepted = true;
else
e.Accepted = false;
编辑:我尝试在 View 上实现 Filter 属性,而不是设置 EventHandler:
myCollectionView = (BindingListCollectionView)myCollectionViewSource.View;
myCollectionView.Filter = new Predicate<object>(Contains);
public bool Contains(object de)
TSCHEDE scheda = de as TSCHEDE;
return (scheda.KLINEA == 990);
现在我得到了不太有用异常:
System.NotSupportedException:不支持指定的方法。 在 System.Windows.Data.CollectionView.set_Filter(Predicate`1 值)
编辑
XAML 代码:
<UserControl.Resources>
<CollectionViewSource x:Key="tSCHEDEViewSource" d:DesignSource="d:DesignInstance my:TSCHEDE, CreateList=True" >
</CollectionViewSource>
<DataTemplate x:Key="SchedaTemplate">
<StackPanel Orientation="Horizontal" >
<TextBlock Text="Binding Path=KSCHEDA" Width="60"></TextBlock>
<TextBlock Text="Binding Path=DArticolo" Width="200"></TextBlock>
<TextBlock Text=" - " Width="40"></TextBlock>
<TextBlock Text="Binding Path=DSTORICO" Width="150"></TextBlock>
</StackPanel>
</DataTemplate>
</UserControl.Resources>
<Grid Background="PapayaWhip" DataContext="StaticResource tSCHEDEViewSource" DataContextChanged="StartHere" Name="rootGrid">
<ComboBox ItemTemplate="StaticResource SchedaTemplate" Grid.Column="1" Grid.Row="1" Height="23" HorizontalAlignment="Left" ItemsSource="Binding" Margin="23,129,0,0" Name="tSCHEDEComboBox1" SelectedValuePath="KSCHEDA" VerticalAlignment="Top" Width="393">
<ComboBox.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel />
</ItemsPanelTemplate>
</ComboBox.ItemsPanel>
</ComboBox>
</Grid>
现在我认为问题出在 XAML 绑定中,而不是背后的代码中......
【问题讨论】:
【参考方案1】:检查一下
1) CollectionView Filtering
过滤需要一个委托(谓词),过滤将基于该委托(谓词)。 Predicate 根据它返回的值 true 或 false 接收项目,它选择或取消选择一个元素。
this.Source.Filter = item =>
ViewItem vitem = item as ViewItem;
return vItem != null && vitem.Name.Contains("A");
;
2) FIltering the data Dynamically
【讨论】:
我已经关注了你的第一个链接,但过了一会儿,事情变得有点太复杂了......最重要的是,我从 myCollectionViewSource.View 得到的是一个 ICollectionView,它似乎没有支持过滤排序(属性 CanSort,CanFilter 为 false)在 XAML 中我有:最后我找到了一个解决方案,也发布了in this question 显式声明集合的类型:
CollectionViewType="ListCollectionView"
所以在 XAML 中添加了 Collection 类型:
<CollectionViewSource x:Key="tSCHEDEViewSource" d:DesignSource="d:DesignInstance my:TSCHEDE, CreateList=True" CollectionViewType="ListCollectionView">
</CollectionViewSource>
现在事件处理程序在代码中起作用了:
myCollectionViewSource.Filter += new FilterEventHandler(filterSource);
唯一的遗憾是我不明白为什么,对于看似如此简单的事情,我必须在 XAML 中“手动”强制它??? 对我来说,这似乎是一种 hack,而且很容易出错......
【讨论】:
你不讨厌有人在不发表评论的情况下投反对票吗? 也许他们收到了这个错误 -CollectionViewType property can only be set during Initialization.
@Warlord099 这很奇怪。我们从不抱怨投票……只是一个想法。但是,是的,我们几乎可以肯定它已经完成了,因为评论/帖子帮助了这个人。
@Yatin 这真的不是那么奇怪。如果答案已经正确/有用,那么可能没有其他任何东西可以通过添加来提供好处。但是,如果答案不正确/没有帮助,那么解释原因总是有好处的。无论哪种方式,尽管两年前我发表初步评论时曾多次投反对票,但现在这是公认的答案。
如果您收到错误“CollectionViewType 属性只能在初始化期间设置。”,只需将 CollectionViewType 设置为 XAML 中的第一个属性,然后再设置任何其他属性。我知道这个答案很旧,但也许这对某人有帮助。【参考方案3】:
<TextBox x:Name="FilterTextBox">
<b:Interaction.Triggers>
<b:EventTrigger EventName="TextChanged">
<b:CallMethodAction
MethodName="Refresh"
TargetObject="Binding View, BindsDirectlyToSource=True, Source=StaticResource tSCHEDEViewSource" />
</b:EventTrigger>
</b:Interaction.Triggers>
</TextBox>
【讨论】:
以上是关于CollectionViewSource,如何过滤数据?的主要内容,如果未能解决你的问题,请参考以下文章
wpf CollectionViewSource 分组后 如何控制 展开和折叠
CollectionViewSource+PropertyGroupDescription - 组中的项目数
检查 CollectionViewSource 中的行是不是是新行