With WPF 4.0, when an item in a collection was added or removed, the CollectionView
interface that it belonged to had its filtering, sorting, and ordering updated. However, this did not happen when we modified one of its item's properties.
Now, with WPF 4.5, we can implement this behavior in real-time with the new ICollectionViewLiveShaping
interface, so if the data is updated, so will its filtering, sorting, and ordering. Let's see how it's done.
Here we are going to see how to implement the ICollectionViewLiveShaping
interface to make our collection update its sorting of the collection of data and will make it change over time as well.
WPFLiveShaping
.BaseClass.cs
from the Implementing asynchronous error handling with INotifyDataErrorInfo recipe, which provides an implementation of the INotifyDataErrorInfo
and the INotifyPropertyChanged
interfaces.BookModel.cs
, adding the following code:public class BooksModel : BaseClass { private string name; public string Name { get { return name; } set { name = value; OnPropertyChanged("Name"); } } private String isbn; public String ISBN { get { return isbn; } set { isbn = value; OnPropertyChanged("ISBN"); } } private Double bookPrice; public Double BookPrice { get { return bookPrice; } set { bookPrice = value; OnPropertyChanged("BookPrice"); } } }
MainWindow.xaml.cs
class:public partial class MainWindow : Window { public ObservableCollection<BooksModel> myBooks { get; set; } DispatcherTimer dt = new DispatcherTimer(); public ICollectionViewLiveShaping cvls; public MainWindow() { InitializeComponent(); InitializeData(); BindData(); StartUpdatingData(); } private void InitializeData() { myBooks = new ObservableCollection<BooksModel>(); Random r = new Random(DateTime.Now.Millisecond); for (int i = 0; i < 15; i++) { BooksModel bm = new BooksModel() { BookPrice = r.Next(1, 10), ISBN = i.ToString(), Name = "Book Nº" + i.ToString() }; myBooks.Add(bm); } } private void BindData() { cvls = (ICollectionViewLiveShaping)CollectionViewSource.GetDefaultView(myBooks); cvls.IsLiveSorting = true; liveShapingDataGrid.ItemsSource = (IEnumerable)cvls; } private void StartUpdatingData() { dt.Tick += dt_Tick; dt.Interval = new TimeSpan(0, 0, 0, 0, 500); dt.Start(); } void dt_Tick(object sender, EventArgs e) { foreach (BooksModel bm in myBooks) { Random r = new Random(DateTime.Now.Millisecond); bm.BookPrice = r.Next(1, 10); } } }
MainWindow.xaml
class, we will add two DataGrid
controls that split the view vertically with the following XAML code:<Grid> <Grid.ColumnDefinitions> <ColumnDefinition/> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition Height="30"/> <RowDefinition/> </Grid.RowDefinitions> <DataGrid x:Name="liveShapingDataGrid" AutoGenerateColumns="False" IsReadOnly="True" Margin="0,30,0.4,0.4" Grid.RowSpan="2"> <DataGrid.Columns> <DataGridTextColumn Header="Name" Binding="{Binding Name}" Width="90"/> <DataGridTextColumn Header="ISBN" Binding="{Binding ISBN}" Width="60"/> <DataGridTextColumn Header="Price" Binding="{Binding BookPrice}" Width="50" /> </DataGrid.Columns> </DataGrid> <Label Content="DataGrid With LiveShaping" FontWeight="Bold" Margin="0,0,0.4,0.4"/> </Grid>
DataGrid
, so it gets ordered in an ascending way. Notice that the ordering of the elements is updated live as the values change, as shown in the following screenshot:We started by creating a BooksModel
class with a double BookPrice
property.
Next, in the MainWindow.xaml
code, we created an ObservableCollection
interface of BooksModel
entities, which we initialized and populated with a few elements on the InitializeData()
method.
We did our magic on the BindData()
method, getting the default CollectionView
from our ObservableCollection
and casting it as ICollectionViewLiveShaping
, with the following instruction:
cvls = (ICollectionViewLiveShaping)CollectionViewSource.GetDefaultView(myBooks);
We enabled the real-time sorting for the resulting ICollectionViewLiveShaping
interface. Next, we set it as ItemsSource
of DataGrid
, casting this CollectionViewLiveShaping
interface into an IEnumerable
.
We then created the StartUpdatingData()
method, configuring DispatcherTimer
to run every half second and update the price of the books, so we could see some action, live from DataGrid
. The method simply runs over all the BooksModel
elements and updates their price with a random generated value.
There is nothing special about the view, we just created DataGrid
to display the three properties of BookModel
.
Finally, we executed the application, ordered the DataGrid
by its price header, and let the real-time ordering happen live. We could observe how the ordering reacts to the property changes taking place every half second through our dispatcher timer.
It would be interesting to explore the other options of the ICollectionViewLiveShaping
interface, such as IsLiveFiltering
and IsLiveGrouping
.
We also have the option of changing how the collection behaves. It is possible to deactivate its LiveFiltering
, LiveGrouping
, and LiveSorting
options with the CanChangeLiveFiltering
, CanChangeLiveSorting
, and CanChangeLiveGrouping
properties.
This interface is implemented by the ListCollectionView
, BindingListCollectionView
, ItemCollection
, and CollectionViewSource
classes by default, thanks to WPF 4.5.