简体   繁体   English

CollectionViewSource,如何过​​滤数据?

[英]CollectionViewSource, how to filter data?

I am binding a ComboBox to Entities but I want the data filtered.我正在将 ComboBox 绑定到实体,但我想要过滤数据。

Up to now I have tried two ways:到目前为止,我尝试了两种方法:

  • "simple" one: Apply the filter directly to the ObjectSet throught LINQ to Entities “简单”一:通过LINQ to Entities直接将过滤器应用到ObjectSet
  • setting a filtering event handler as described on msdn按照msdn 上的描述设置过滤事件处理程序

I am satisfied by the first approach, above all because the query generated to the database contains a WHERE clause, so not all the whole data have to be retrieved from the remote db....我对第一种方法感到满意,最重要的是因为生成到数据库的查询包含一个 WHERE 子句,因此不必从远程数据库中检索所有数据....

However, the #2 approach is by far more flexible, if at runtime i'd like to change the filtering applied... I have followed the example on msdn, but I get an exception, why?但是,#2 方法要灵活得多,如果在运行时我想更改应用的过滤...我已经按照 msdn 上的示例进行操作,但出现异常,为什么?

So, my questions are:所以,我的问题是:
1. Which approach is better 1. 哪种方法更好
2. Why I get the exception? 2. 为什么会出现异常?

Here is my code:这是我的代码:

 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;
            }
        }
    }

EDIT : I have tried implementing the Filter property on the View rather than setting the 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);
    }

And now I get the not so useful exception:现在我得到了一个不太有用的异常:

System.NotSupportedException: Specified method is not supported. System.NotSupportedException:不支持指定的方法。 at System.Windows.Data.CollectionView.set_Filter(Predicate`1 value)在 System.Windows.Data.CollectionView.set_Filter(Predicate`1 值)

EDIT编辑

XAML code: 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>

Now I am thinking the problem is in XAML Binding, not in code behind...现在我认为问题出在 XAML 绑定中,而不是在背后的代码中...

Check this检查这个

1) CollectionView Filtering 1) CollectionView 过滤

Filtering requires a delegate (Predicate) based on which the filter will occur.过滤需要一个委托(Predicate),过滤将基于它发生。 The Predicate takes in the item an based on the value true or false it returns, it selects or unselect an element. Predicate 根据它返回的值 true 或 false 接收项目 an,它选择或取消选择一个元素。

this.Source.Filter = item => {
    ViewItem vitem = item as ViewItem;
    return vItem != null && vitem.Name.Contains("A");
};

2) FIltering the data Dynamically 2) 动态过滤数据

Al last I have found a solution, as posted also in this question to explicitly declare the type of the Collection:最后我找到了一个解决方案,正如在这个问题中也发布的那样,明确声明集合的类型:

CollectionViewType="ListCollectionView" CollectionViewType="ListCollectionView"

So in XAML added the Collection type:所以在 XAML 中添加了 Collection 类型:

<CollectionViewSource x:Key="tSCHEDEViewSource" d:DesignSource="{d:DesignInstance my:TSCHEDE,  CreateList=True}" CollectionViewType="ListCollectionView">
    </CollectionViewSource>

And in code now the Event Handler works:现在在代码中,事件处理程序起作用了:

myCollectionViewSource.Filter += new FilterEventHandler(filterSource);

The only regret is that I did not understand why, for something apparently so simple, I have to force it "by hand" in XAML ???唯一的遗憾是我不明白为什么,对于显然如此简单的事情,我必须在 XAML 中“手动”强制它??? To me this seems like an hack, and also very error prone...对我来说,这似乎是一种黑客行为,而且很容易出错......

<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>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM