CollectionViewSource, how to filter data?

[亡魂溺海] 提交于 2019-12-09 00:37:57

问题


I am binding a ComboBox to Entities but I want the data filtered.

Up to now I have tried two ways:

  • "simple" one: Apply the filter directly to the ObjectSet throught LINQ to Entities
  • setting a filtering event handler as described on 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....

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?

So, my questions are:
1. Which approach is better
2. Why I get the exception?

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. at System.Windows.Data.CollectionView.set_Filter(Predicate`1 value)

EDIT

XAML code:

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


回答1:


Check this

1) CollectionView Filtering

Filtering requires a delegate (Predicate) based on which the filter will occur. The Predicate takes in the item an based on the value true or false it returns, it selects or unselect an element.

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"

So in XAML added the Collection type:

<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 ??? To me this seems like an hack, and also very error prone...



来源:https://stackoverflow.com/questions/14497506/collectionviewsource-how-to-filter-data

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!