Script 3: Collection View Class in Studio for WinRT XAML


image


  


Collection View Class 


Get a more powerful implementation of the ICollectionView interface with ComponentOne CollectionView for WinRT XAML. The C1CollectionView class delivers missing functionality like sorting, filtering, grouping, and modifying any collection. Use C1CollectionView as you would use CollectionViewSource in your Windows Store apps to instantly get more functionality without sacrifice.


Features




  • Sorting, Filtering, and Grouping


The C1CollectionView class and IC1CollectionView interface give you support for sorting, filtering, and grouping collections in WinRT XAML apps. The object model and functionality are virtually identical to those in the ICollectionView interface provided in WPF, Silverlight, and Windows Phone, so there is no learning curve.


image


 


  




  • More Powerful than CollectionViewSource


The standard ICollectionView interface and CollectionViewSource implementations in WinRT are limited compared to WPF and Silverlight. For instance, the WinRT implementation of ICollectionView does not support sorting, filtering, or editing. The C1CollectionView class adds these missing elements so you can achieve the functionality you need.




  • Use with Any Control


C1CollectionView implements the ICollectionView interface completely, so any standard items control can use it as a data source. Many ComponentOne controls make use of the C1CollectionView class internally and automatically, but the interface is public so you can use it yourself with any control.


  


image


 


  




  • Editable Live Rowsets


C1CollectionView provides a live rowset. Any changes made to the data are automatically propagated to the underlying collection. C1CollectionView also adds and implements the IEditableCollectionView interface, cloned from WPF and Silverlight, so you get a better editing experience including pressing escape to cancel all changes made to the item being edited.




  • Familiar Object Model


The IC1CollectionView interface is based on the WPF and Silverlight ICollectionView, so you will be familiar with sorting, filtering, and grouping your collections. The C1CollectionView class is also compatible with WPF, Silverlight, and Windows Phone versions so you can easily re-use your code.


 


Getting Started with Collection View


 


We will build an app that binds a c1CollectionView to a ListBox and a Grid.


image


  


Start New C# Windows Store Blank App Project, name the project Collection.


  


image


Let’s set up our UI using a ListBox and GridView to show our data collection. Add this to the Grid:



        <Grid.RowDefinitions>
<
RowDefinition Height="Auto"/>
<
RowDefinition />
Grid.RowDefinitions>
<
Grid Grid.Row="1">
Grid>


  


Within the grid for Row 1 add these column definitions, ListBox and GridView:

 



            <Grid.ColumnDefinitions>
<
ColumnDefinition Width="300"/>
<
ColumnDefinition />
Grid.ColumnDefinitions>
<
Grid.RowDefinitions>
<
RowDefinition Height="Auto"/>
<
RowDefinition />
Grid.RowDefinitions>

Add a ListBox:


        



               
<TextBlock Text="Grouped ListBox" FontSize="18" Padding="5"/>
<
ListBox Name="listBox1" Grid.Row="1" >
<
ListBox.GroupStyle>
<
GroupStyle>
<
GroupStyle.HeaderTemplate>
<
DataTemplate>
<
Border MinHeight="20" MinWidth="70"
Background="{StaticResource ListViewItemOverlayBackgroundThemeBrush }" Padding="5">
<
TextBlock Text="{Binding}" Foreground="White" />
Border>
DataTemplate>
GroupStyle.HeaderTemplate>
GroupStyle>
ListBox.GroupStyle>
<
ListBox.ItemTemplate>
<
DataTemplate>
<
Border>
<
StackPanel Orientation="Horizontal">
<
CheckBox IsChecked="{Binding Active}" IsEnabled="False"/>
<
TextBlock Text="{Binding Name}"/>
<
TextBlock Text=" from "/>
<
TextBlock Text="{Binding Country}"/>
StackPanel>
Border>
DataTemplate>
ListBox.ItemTemplate>
ListBox>

  


 Add GridView and TextBox


  



                      
<TextBlock Text="Grouped GridView" Grid.Column="1" FontSize="18" Padding="5"/>
<
GridView Name="gridView1" Grid.Row="1" Grid.Column="1" Margin="10,0,0,0">
<
GridView.GroupStyle>
<
GroupStyle>
<
GroupStyle.HeaderTemplate>
<
DataTemplate>
<
Border MinHeight="20" MinWidth="70"
Background="#FF959595" Padding="5">
<
TextBlock Text="{Binding}" Foreground="White" VerticalAlignment="Center"/>
Border>
DataTemplate>
GroupStyle.HeaderTemplate>

<
GroupStyle.Panel>
<
ItemsPanelTemplate>
<
VariableSizedWrapGrid Orientation="Vertical" Height="400" />
ItemsPanelTemplate>
GroupStyle.Panel>
GroupStyle>
GridView.GroupStyle>

<
GridView.ItemTemplate>
<
DataTemplate>
<
Grid Width="200" HorizontalAlignment="Left">
<
StackPanel Orientation="Horizontal">
<
CheckBox Grid.Column="1" IsChecked="{Binding Active}" IsEnabled="False"/>
<
TextBlock Text="{Binding Name}"/>
<
TextBlock Text=", "/>
<
TextBlock Text="{Binding Country}"/>
StackPanel>
Grid>
DataTemplate>
GridView.ItemTemplate>
GridView>

 



 


Now let’s move to code and set up our simple data model. Add a Folder to the project for Data

  


image


 


 


Add two classes to the Data Folder… BaseObject and Customer…


  


image


 


 


 


In BaseObject.cs, modify the BaseObject class to look like this…


  



using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Reflection;

namespace collection.Data
{
public class BaseObject : INotifyPropertyChanged
{
// ** INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propName)
{
if (PropertyChanged != null)
PropertyChanged(
this, new PropertyChangedEventArgs(propName));
}
protected bool SetValue(ref T field, T value, string propertyName)
{
if (!EqualityComparer.Default.Equals(field, value))
{
field = value;
OnPropertyChanged(propertyName);
return true;
}
return false;
}
}
///
/// Object that implements INotifyPropertyChanged and IEditableObject.
///

public class BaseEditableObject : BaseObject, IEditableObject
{
object _clone;
public void BeginEdit()
{
_clone =
this.MemberwiseClone();
}
public void CancelEdit()
{
if (_clone != null)
{
foreach (var pi in this.GetType().GetRuntimeProperties())
{
if (pi.CanRead && pi.CanWrite)
{
var value = pi.GetValue(_clone);
pi.SetValue(
this, value);
}
}
}
_clone =
null;
}
public void EndEdit()
{
_clone =
null;
}
}
}

 


  In Customer.cs, modify the Customer class to look like this



 
 



using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using C1.Xaml;
using System.Collections.ObjectModel;

namespace collection.Data
{
public class Customer : BaseEditableObject
{
int _id;
string _name, _country;
DateTime _created;
double _value, _sales, _assets, _growth;
bool _active;

static int _ctr;
static Random _rnd = new Random();
static string[] _countries = "Austria|Belgium|Canada|Denmark|Egypt|Finland|Guatemala|Haiti|Ireland|Jamaica".Split('|');
static string[] _names = "Albert|Bill|Charlie|Dave|Ed|Fred|George|Harry|Ian|Jerry".Split('|');

public static ObservableCollection<Customer> GetCollection(int count)
{
ObservableCollection<Customer> ret = new ObservableCollection<Customer>();
for (int i = 0; i < count; i++)
ret.Add(
new Customer());
return ret;
}

public Customer()
{
ID = _ctr++;
Name = _names[_rnd.Next() % _names.Length];
Country = _countries[_rnd.Next() % _countries.Length];
Created =
DateTime.Today.AddDays(_rnd.Next(-40, -30));
for (int i = 0; i < 100; i++)
{
Assets += _rnd.NextDouble() * 100;
Value += _rnd.NextDouble() * 1000;
Sales += _rnd.NextDouble() * 100;
}
if (_rnd.NextDouble() < .05)
{
Value = -Value;
Assets = -Assets;
}
if (_rnd.NextDouble() < .05)
{
Growth = -Growth;
}
Growth = _rnd.NextDouble();
Active = _rnd.NextDouble() > .5;
}
public int ID
{
get { return _id; }
set { SetValue(ref _id, value, "ID"); }
}
public string Name
{
get { return _name; }
set { SetValue(ref _name, value, "Name"); }
}
public string Country
{
get { return _country; }
set { SetValue(ref _country, value, "Country"); }
}
public DateTime Created
{
get { return _created; }
set { SetValue(ref _created, value, "Created"); }
}
public double Sales
{
get { return _sales; }
set { SetValue(ref _sales, value, "Sales"); }
}
public double Growth
{
get { return _growth; }
set { SetValue(ref _growth, value, "Growth"); }
}
public double Assets
{
get { return _assets; }
set { SetValue(ref _assets, value, "Assets"); }
}
public double Value
{
get { return _value; }
set { SetValue(ref _value, value, "Value"); }
}
public bool Active
{
get { return _active; }
set { SetValue(ref _active, value, "Active"); }
}
}
}

 


Add a reference to the C1 Studio for WinRT:


 

image


 



 


 

Edit MaiPage.xaml.cs


 


Modify class MainPage as follows to bind the Collection View to the ListBox and GridView and look as follows:



using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
using C1.Xaml;
using System.Collections.ObjectModel;
using collection.Data;

// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=234238

namespace collection
{
///
/// An empty page that can be used on its own or navigated to within a Frame.
///

public sealed partial class MainPage : Page
{
private C1CollectionView _c1CollectionView;
public MainPage()
{

this.InitializeComponent();
Loaded += MainPage_Loaded;
}

void MainPage_Loaded(object sender, RoutedEventArgs e)
{
ObservableCollection<Customer> customers = Customer.GetCollection(30);
_c1CollectionView =
new C1CollectionView();
_c1CollectionView.GroupDescriptions.Add(
new PropertyGroupDescription("Country"));
_c1CollectionView.SortDescriptions.Add(
new SortDescription("Name", ListSortDirection.Ascending));
_c1CollectionView.SourceCollection = customers;

listBox1.ItemsSource = _c1CollectionView;
gridView1.ItemsSource = _c1CollectionView;
}

///
/// Invoked when this page is about to be displayed in a Frame.
///

///
Event data that describes how this page was reached. The Parameter
/// property is typically used to configure the page.
protected override void OnNavigatedTo(NavigationEventArgs e)
{
}
}
}

  


Notice that we instantiate a C1CollectionView by settings its SourceCollection property to our collection object. We then apply grouping and sort descriptors to the C1CollectionView and they will apply to the data collection! Isn’t that cool?


 


Press F5 and you will see the c1CollectionView bound to both the ListBox and GridView.


 image


Online Documentation for CollectionView


 


Next Part in the blog series:


WinRT XAML (Part 4) Calendar