Collections
Collections are the primary structures you will use to manipulate data within your application. These classes implement common interfaces that provide consistent methods for querying and managing the data in the collection. Collections are often bound to UI controls. In the Wintellog example, a collection of blogs provides the grouped few and is bound to the GridView control. A collection of posts within the blogs feed the detail view within a group.
The Windows Runtime has a set of commonly used collection types. These types are mapped automatically to .NET Framework types by the CLR. In code, you won’t reference the Windows Runtime types directly. Instead, you manipulate the .NET equivalent, and the CLR handles conversion automatically. Table 6.3 lists the Windows Runtime type and the .NET equivalent along with a brief description and example classes that implement the interface.
Table 6.3. Collection Types in the Windows Runtime and .NET
WinRT |
.NET Framework |
Example |
Description |
IIterable<T> |
IEnumerable<T> |
Most collection types |
Provides an interface to support iteration for a collection |
IIterator<T> |
IEnumerator<T> |
Exposed via collection type |
The interface for performing iteration over a collection |
IVector<T> |
IList<T> |
List<T> |
A collection that can be individually accessed via an index |
IVectorView<T> |
IReadOnlyList<T> |
ReadOnly Collection<T> |
Version of an indexed collection that cannot be modified |
IMap<K,V> |
IDictionary<K,V> |
Dictionary<K,V> |
A collection of values that are referenced by keys |
IMapView<K,V> |
IReadOnly Dictionary<K,V> |
ReadOnly Dictionary<K,V> |
Version of a collection with key/value pairs that cannot be modified |
IBindableIterable |
IEnumerable |
Exposed via non-generic collections |
Supports iteration over a nongeneric collection |
IBindableVector |
IList |
Custom classes that implement IList |
Supports a nongeneric collection that can be referenced by index |
One important list that is not mapped to the Windows Runtime is the ObservableCollection<T>. This is a special list because it works with the data-binding system you learned about in Chapter 3, Extensible Application Markup Language (XAML). The ObservableCollection<T> implements the INotifyCollectionChanged interface, which is designed to notify listeners when the list changes—for example, when items are added or removed or the entire list is refreshed.
For performance, the data-binding system does not constantly examine the lists you bind to UI controls. Instead, the initially bound list is used to generate the controls on the display. When you manipulate the list, the data-binding system receives a notification through the CollectionChanged event and can use the list of added and removed items to refresh the controls being displayed. Without the interface, the only way to have a list refresh the UI is to raise a PropertyChanged event for the property that exposes the list. This is inefficient because it results in the entire list being refreshed rather than only the items that changed.
Language Integrated Query (LINQ)
One major advantage of using collections is the ability to write queries against them using Language Integrated Query (LINQ). This feature extends the language syntax of C# to provide patterns for querying and updating data. LINQ itself works with providers for different types of data storage, such as a database backend (SQL) or an XML document. The LINQ to Objects provider supports classes that implement the IEnumerable interface and therefore can be used with most collections.
LINQ to Objects is implemented as a set of extension methods to the existing IEnumerable interface. These extension methods are declared in the System.Linq namespace. Extension methods enable you to add methods to existing types without having to create a new type. They are a special type of static method that use a special this modifier for the first parameter. You can learn more about extension methods online at http://msdn.microsoft.com/en-us/library/bb383977(v=vs.110).aspx.
There are three fundamental steps involved with a LINQ query. The first step is to provide the data source or collection you will query against. The second step is to provide the query, and the final step is to execute the query. It’s important to understand that creating a query does not actually invoke any action against the data source. The query only executes when you need it and then only processes results as you obtain them. This is referred to as deferred execution.
LINQ supports a variety of query operations. It also supports multiple syntaxes for querying data. The BlogDataSource class in the Wintellog project has a method called LinqExamples. This method is never called, but you can use it to see the various types of LINQ queries and syntaxes. The first syntax is referred to as LINQ query syntax and resembles the T-SQL syntax you may be used to working with in databases. The second syntax is method-oriented and is referred to as method syntax. The method syntax is constructed using lambda expressions.
The following series of examples shows both syntaxes, starting with the query syntax.
Queries
You can use simple queries to parse collections and return the properties of interest. The following examples produce a list of strings that represent the titles from the blog groups:
var query = from g in GroupList select g.Title; var query2 = GroupList.Select(g => g.Title);
Filters
Filters allow you to restrict the data returned by a query. You can filter using common functions that compare and manipulate properties. In the following examples, the list is filtered to only those groups with a title that starts with the letter “A.”
var filter = from g in GroupList where g.Title.StartsWith("A") select g; var filter2 = GroupList.Where(g => g.Title.StartsWith("A"));
Sorting
You can sort in both ascending and descending order and across multiple properties if needed. The following queries will sort the blogs by title:
var order = from g in GroupList orderby g.Title select g; var order2 = GroupList.OrderBy(g => g.Title);
Grouping
A powerful feature of LINQ is the ability to group similar results. This is especially useful in Windows 8 applications for providing the list for controls that support groups. The following queries will create groups based on the first letter of the blog title:
var group = from g in GroupList group g by g.Title.Substring(0, 1); var group2 = GroupList.GroupBy(g => g.Title.Substring(0, 1));
Joins and Projections
You can join multiple sources together and project to new types that contain only the properties that are important to you. The following query syntax will join the items from one blog to another based on the date posted and then project the results to a new class with source and target properties for the title:
var items = from i in GroupList[0].Items join i2 in GroupList[1].Items on i.PostDate equals i2.PostDate select new { SourceTitle = i.Title, TargetTitle = i2.Title };
Here is the same query using lambda expressions:
var items2 = GroupList[0].Items.Join( GroupList[1].Items, g1 => g1.PostDate, g2 => g2.PostDate, (g1, g2) => new { SourceTitle = g1.Title, TargetTitle = g2.Title });
This section only touched the surface of what is possible with LINQ expressions. You can learn more about LINQ by reading the articles and tutorials available online at http://msdn.microsoft.com/en-us/library/bb383799(v=vs.110).aspx.