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 中我有: 跨度> 程序员天生就是为了做复杂的事情:-) 事实上,这就是答案。【参考方案2】:

最后我找到了一个解决方案,也发布了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,如何过​​滤数据?的主要内容,如果未能解决你的问题,请参考以下文章

在 CollectionViewSource 上触发过滤器

wpf CollectionViewSource 分组后 如何控制 展开和折叠

CollectionViewSource+PropertyGroupDescription - 组中的项目数

检查 CollectionViewSource 中的行是不是是新行

为啥使用 CollectionViewSource.SortDescriptions 排序很慢?

[Wpf]在C#中添加 collectionViewSource