集合视图
基于绑定源集合,它允许基于排序、筛选和分组查询来导航并显示源集合,而无需更改基础源集合本身。 集合视图还维护一个指向集合中当前项的指针。
创建并使用视图的一种方式是直接实例化视图对象,然后将它用作绑定源。
<Window.Resources> <CollectionViewSource Source="{Binding Source={x:Static Application.Current}, Path=AuctionItems}" x:Key="listingDataView" /> </Window.Resources> <ListBox Name="Master" Grid.Row="2" Grid.ColumnSpan="3" Margin="8" ItemsSource="{Binding Source={StaticResource listingDataView}}" />
若要为同一集合创建另一个视图,则可以创建另一个 CollectionViewSource 实例,并为其提供不同的 x:Key
名称。
下表显示作为默认集合视图创建或由 CollectionViewSource 根据源集合类型创建的视图数据类型。
源集合类型 | 集合视图类型 | 说明 |
---|---|---|
IEnumerable | 基于 CollectionView 的内部类型 | 无法对项进行分组。 |
IList | ListCollectionView | 最快。 |
IBindingList | BindingListCollectionView |
排序
private void AddSortCheckBox_Checked(object sender, RoutedEventArgs e) { // Sort the items first by Category and then by StartDate listingDataView.SortDescriptions.Add(new SortDescription("Category", ListSortDirection.Ascending)); listingDataView.SortDescriptions.Add(new SortDescription("StartDate", ListSortDirection.Ascending)); }
筛选
private void AddFilteringCheckBox_Checked(object sender, RoutedEventArgs e) { if (((CheckBox)sender).IsChecked == true) listingDataView.Filter += ListingDataView_Filter; else listingDataView.Filter -= ListingDataView_Filter; } private void ListingDataView_Filter(object sender, FilterEventArgs e) { // Start with everything excluded e.Accepted = false; // Only inlcude items with a price less than 25 if (e.Item is AuctionItem product && product.CurrentPrice < 25) e.Accepted = true; }
分组
// This groups the items in the view by the property "Category" var groupDescription = new PropertyGroupDescription(); groupDescription.PropertyName = "Category"; listingDataView.GroupDescriptions.Add(groupDescription);
<Window.Resources> <src:Places x:Key="places"/> <CollectionViewSource Source="{StaticResource places}" x:Key="cvs"> <CollectionViewSource.SortDescriptions> <scm:SortDescription PropertyName="CityName"/> </CollectionViewSource.SortDescriptions> <CollectionViewSource.GroupDescriptions> <dat:PropertyGroupDescription PropertyName="State"/> </CollectionViewSource.GroupDescriptions> </CollectionViewSource> <ListBox ItemsSource="{Binding Source={StaticResource cvs}}" DisplayMemberPath="CityName" Name="lb"> <ListBox.GroupStyle> <x:Static Member="GroupStyle.Default"/> </ListBox.GroupStyle> </ListBox>
</Window.Resources>
数据变化时,排序、筛选、分组的结果并不会变化,需要手动调用CollectionView的Refresh方法:FindResource("cvsActors") as CollectionViewSource).View.Refresh();
可以使用LiveFilteringProperties等属性以获得实时变化
<CollectionViewSource x:Key="cvsActors" Source="{Binding ActorList}" IsLiveFilteringRequested="True"> <CollectionViewSource.LiveFilteringProperties> <s:String>Name</s:String> </CollectionViewSource.LiveFilteringProperties> </CollectionViewSource>
当前项
由于 WPF 只通过使用视图(你指定的视图或集合的默认视图)绑定到集合,因此集合的所有绑定都有一个当前项指针。 绑定到视图时,Path
值中的斜杠(“/”)字符用于指定视图的当前项。 在下面的示例中,数据上下文是一个集合视图。 第一行绑定到集合。 第二行绑定到集合中的当前项。 第三行绑定到集合中当前项的 Description
属性。
<Button Content="{Binding }" /> <Button Content="{Binding Path=/}" /> <Button Content="{Binding Path=/Description}" />
只需将两个或更多控件绑定到同一视图即可实现主-从方案。
<ListBox Name="Master" Grid.Row="2" Grid.ColumnSpan="3" Margin="8" ItemsSource="{Binding Source={StaticResource listingDataView}}" /> <ContentControl Name="Detail" Grid.Row="3" Grid.ColumnSpan="3" Content="{Binding Source={StaticResource listingDataView}}" ContentTemplate="{StaticResource detailsProductListingTemplate}" Margin="9,0,0,0"/>
此绑定有效是因为将单一实例对象(在本例中为 ContentControl)绑定到集合视图时,它会自动绑定到该视图的 CurrentItem。
<DockPanel DataContext="{Binding Source={StaticResource MyList}}"> <StackPanel> <Label>My Soccer Leagues</Label> <ListBox ItemsSource="{Binding}" ItemTemplate="{StaticResource dataTemplate}" IsSynchronizedWithCurrentItem="true"/> </StackPanel> <StackPanel> <Label Content="{Binding XPath=@name}"/> <ListBox Name="divisionsListBox" ItemsSource="{Binding XPath=Division}" ItemTemplate="{StaticResource dataTemplate}" IsSynchronizedWithCurrentItem="true"/> </StackPanel> <StackPanel> <Label Content="{Binding XPath=@name}"/> <ListBox DataContext="{Binding ElementName=divisionsListBox, Path=SelectedItem}" ItemsSource="{Binding XPath=Team}" ItemTemplate="{StaticResource dataTemplate}"/> </StackPanel> </DockPanel>
在数据集合视图中导航
//OnButton is called whenever the Next or Previous buttons //are clicked to change the currency private void OnButton(Object sender, RoutedEventArgs args) { Button b = sender as Button; switch (b.Name) { case "Previous": myCollectionView.MoveCurrentToPrevious(); if (myCollectionView.IsCurrentBeforeFirst) { myCollectionView.MoveCurrentToLast(); } break; case "Next": myCollectionView.MoveCurrentToNext(); if (myCollectionView.IsCurrentAfterLast) { myCollectionView.MoveCurrentToFirst(); } break; o = myCollectionView.CurrentItem as Order; // TODO: do something with the current Order o } }