Archive for the ‘Collections’ Category

ItemsControl: 'E' is for Editable Collection

Monday, October 20th, 2008

Dear Dr. WPF,

As of late, a serein has come upon me in the world of wpf and databinding, hence I’m writing to you in my desperate search for some kind of remedy before there will be a hey rube.

Whilst having an ObservableCollection of “Person” objects, and creating a collectionview for this and also adding a SortDescription on a “Name” property on the “Person” object, I noticed that if I change the “Name” property on one of the objects (they are shown in a listbox, having the “Name” property databound to a textblock), and thereafter calling Refresh() on the CollectionView, the refresh will actually take more than a second with only about 50 items.

Ok, if I measure the call to Refresh() it doesn’t take more than 100 ms or so, but like the call sets in motion alot of other things that will happen after my method has exited, which is understandable since the documentation states that the whole view is recreated and therefore I assume the whole tree of items of the visualtree concerned is re-created too.

If I instead just remove the item, and just re-insert it, it’s as close as I can get to instantaneous. perfect! BUT! Since I’m a quidnunc I won’t be satisfied with this! So I’m asking the great Dr, that has given us all such great in depth knowledge in the past, what can we do about this in a more generic fashion? Can we speed up the “Refresh()” somehow? What would you suggest I do if I have a collection of a type that I don’t know about at compile time? How can I remove / add an item then!

Or am I simply lost in my path to enlightenment ?

I shall not dissert anymore, but hope to hear from the good Dr, perhaps in a blogpost touching this subject as I feel it to be of greater interest to the public health in the land of wpf.

Best regards,
Patient-X


Dear Patient-X,

I’ve been wondering what I could file under the letter ‘E’ in this series, and now you’ve afforded me the perfect opportunity! 🙂

No, you are not lost in your path to enlightenment. The true path will lead you to a new feature in .NET 3.5 SP1 called an “editable” collection view. More on that momentarily… First, let’s examine exactly what is happening in your scenario.

Understanding the ListCollectionView Class

You are binding to a list of items. More specifically, you are binding to a collection of Person objects (namely an ObservableCollection<Person>) that, in turn, implements the IList interface. The binding engine will automatically generate a ListCollectionView for such a collection. The ListCollectionView class provides support for sorting, grouping, and filtering your collection when it is the ItemsSource for an ItemsControl. (See ‘C’ is for Collection for more information.)

For the purposes of this discussion, let’s look at a similar scenario using the following collection of Character objects (borrowed from ‘I’ is for Item Container):

    <src:CharacterCollection x:Key="Characters">
      <src:Character First="Homer" Last="Simpson"
          Gender="Male" Image="images/homer.png" />
      <src:Character First="Marge" Last="Bouvier"
          Gender="Female" Image="images/marge.png" />
      <src:Character First="Bart" Last="Simpson"
          Gender="Male" Image="images/bart.png" />
      <src:Character First="Lisa" Last="Bouvier"
          Gender="Female" Image="images/lisa.png" />
      <src:Character First="Maggie" Last="Simpson"
          Gender="Female" Image="images/maggie.png" />
    </src:CharacterCollection>

To demonstrate grouping and sorting for our collection, we can define a CollectionViewSource object in markup, as shown below:

    <CollectionViewSource x:Key="CharacterCollectionView"
        Source="{Binding Source={StaticResource Characters}}">
      <CollectionViewSource.GroupDescriptions>
        <PropertyGroupDescription PropertyName="Gender"/>
      </CollectionViewSource.GroupDescriptions>
      <CollectionViewSource.SortDescriptions>
        <cm:SortDescription PropertyName="First" />
      </CollectionViewSource.SortDescriptions>
    </CollectionViewSource>

When this CollectionViewSource is set as the ItemsSource of a ListBox, it will yield a view of the collection (namely, a ListCollectionView) in which the characters are grouped by gender and sorted by first name. Here is what the ListBox declaration might look like:

  <ListBox Name="lb" HorizontalAlignment="Center" VerticalAlignment="Center"
      ItemsPanel="{StaticResource HorizontalItemsPanel}"
      ItemsSource="{Binding Source={StaticResource CharacterCollectionView}}"
      ItemContainerStyle="{StaticResource CharacterContainerStyle}">
    <ListBox.GroupStyle>
      <GroupStyle Panel="{StaticResource HorizontalItemsPanel}" />
    </ListBox.GroupStyle>
  </ListBox>

The image below depicts our ListBox with grouping and sorting.

You can download the sample for this post to see the complete item template, item container style, and group item style.

Dynamically Updating Items is Problematic

Ideally, applying a sort order to a CollectionView would result in a grouped and sorted view of the collection that is fully maintained even when items within the collection are changed. Unfortunately, a ListCollectionView only groups and sorts its items when the view is first created (or when new items are added to the source collection, assuming that the source collection is observable). A ListCollectionView will *not* monitor changes to properties on each existing item within the collection.

For example, if you execute code at runtime to dynamically change Bart’s name to “Mandy”, the ListCollectionView will be unaware of that change and the item will not appear in its proper sorted location after the change. Furthermore, if Bart finally gets the operation he deserves (and secretly desires) and his gender is updated accordingly, the changed item will not move to its proper group. Here is some simple code to perform these changes:

    Character bart = lb.Items[0] as Character;
    bart.First = "Mandy";
    bart.Gender = Gender.Female;

The image below depicts the sorting and grouping errors that are present after these changes:

Note, that the item template did indeed update according to the name and gender change (because the Character object raises the appropriate change notifications for these properties), but the ListCollectionView did not update its view of the items. As a result, the changed item is no longer in the correct sort location or group.

Refreshing a CollectionView

If you are using .NET 3.5 or earlier, you can force a CollectionView to be updated at runtime by calling its Refresh() method. Then the items will once again be properly grouped and sorted. Here is a routine that includes the Refresh() call:

    Character bart = lb.Items[0] as Character;
    bart.First = "Mandy";
    bart.Gender = Gender.Female;
    (lb.ItemsSource as ListCollectionView).Refresh();

After calling Refresh(), the modified character now appears in the correct group and sort location, as shown here:

Unfortunately, the Refresh() method results in a complete regeneration of the view. It is a rather drastic operation, to say the least. Furthermore, when a Refresh() occurs within the view, it raises a CollectionChanged notification and supplies the Action as “Reset”. The ItemContainerGenerator for the ListBox receives this notification and responds by discarding all the existing visuals for the items. It then completely regenerates new item containers and visuals. (See ‘I’ is for Item Container and ‘G’ is for Generator for more information on item containers and container generation.) Again, this is a drastic (and often very expensive) operation.

Increasing Refresh Performance is Difficult

You raised the question, “Can we speed up the “Refresh()” somehow?”

Unfortunately, the very nature of the refresh operation makes this difficult. For the mundane reasons, keep reading… otherwise, feel free to skip ahead to A Better Option.

Theoretically, you could derive your own custom collection view from the ListCollectionView class and override its Refresh() method. Then you could perhaps implement a routine that intelligently regenerates the view in a minimalistic manner by comparing the source collection to the view collection.

Such a routine would need to move existing items to their new locations in the view, add items that were not previously present, and remove items that should no longer be present. All of these changes would need to be made per the view’s sorting, grouping, and filter criteria. For each change, the view would need to raise a very specific CollectionChanged notification (Add, Remove, or Move) for consumption by the ItemContainerGenerator of the owning ItemsControl.

Not only would such a synchronization routine be complex, but it is also likely to be even more expensive than simply resetting the entire collection. There will be some number, n, where discrete Add, Remove, and Move change notifications for n or fewer changes is indeed more performant than a single Reset notification. Unfortunately, it will be very difficult to heuristically determine the appropriate value for n.

A Better Option: Remove and Re-Add

A better approach, especially if you are stuck on pre-3.5 SP1 bits, is to do precisely what you describe in your email. Namely, do not call Refresh() at all, but instead, remove the target item from the observable collection, modify its properties, and then re-add it to the collection, as shown here:

    Character bart = lb.Items[0] as Character;
    CharacterCollection characters = FindResource("Characters") as CharacterCollection;
    characters.Remove(bart);
    bart.First = "Mandy";
    bart.Gender = Gender.Female;
    characters.Add(bart);

The ListCollectionView will detect the removal of the old item and raise the appropriate Remove notification so that the ItemContainerGenerator can remove the associated container and visuals. It will also detect the addition of the modified item and insert it at the correct location within its view of the source collection (again, per the grouping, sorting, and filter criteria). Then it will raise the necessary Add notification so that a new item container and item visuals can be generated.

This solution is obviously not perfect! One problem that may not be immediately evident is that adding and removing an item from the source collection effects the ListCollectionView’s notion of currency (“current item”). For example, if the Bart character was the current item before it was removed from the collection, that state will be lost. If this is important to your scenario, you must add additional code around the remove/re-add routine to save and restore currency.

An Even Better Option: IEditableObject

As mentioned earlier, .NET 3.5 SP1 enables an even better approach that solves many of the problems present in the Refresh() and Remove/Re-Add solutions. Namely, it allows you to implement an IEditableObject interface on your datamodel objects (or on your viewmodel objects, if you are using the model-view-viewmodel pattern). This new interface allows for transactional changes (edit, cancel, and commit) on the object.

The framework supports the transactional model by implementing another new interface called IEditableCollectionView on the existing list-based CollectionView classes (ListCollectionView and BindingListCollectionView). This interface works in conjunction with collection items that implement the IEditableObject interface.

In this new approach, when you need to change an item, you can first call the EditItem() method of the collection view, then make the required changes to the item, and finally, call the CommitEdit() method of the collection view. If you decide that you don’t want to commit the changes, you can call the CancelEdit() method of the collection view.

It is worth noting that the ItemCollection class also implements the IEditableCollectionView interface. Since the Items property of an ItemsControl is of type ItemCollection (see ‘C’ is for Collection), it provides handy access to the methods of IEditableCollectionView. As long as you know the source collection is an IList, you can safely call the IEditableCollectionView methods directly on the Items property and the ItemCollection class will delegate the call to the appropriate underlying collection view.

How it Works

In practice, the properties of an “editable” object will rarely be updated directly in code behind. Rather, these properties will be updated via bindings to properties on controls within the UI.

In WPF, it is fairly common to present data using a “view template”. Such a template will often present a readonly view of the data using elements like TextBlock, Image, etc. Then, when it is necessary to edit the data, the view will switch to an “edit template” that contains editable controls like TextBox, ComboBox, CheckBox, etc.

The IEditableObject interface provides three transactional methods: BeginEdit(), CancelEdit(), and EndEdit(). I prefer to expose an additional readonly property on the editable object called IsInEditMode that can be used as a trigger for swapping between the view template and the edit template.

Below is my typical implementation of IEditableObject, as it would be implemented on the Character class in our example:

    #region IEditableObject support

    public Character _cachedCopy = null;

    public void BeginEdit()
    {
        // save object state before entering edit mode
        _cachedCopy = new Character();
        _cachedCopy._first = _first;
        _cachedCopy._last = _last;
        _cachedCopy._image = _image;
        _cachedCopy._gender = _gender;

        // ensure edit mode flag is set
        IsInEditMode = true;
    }

    public void CancelEdit()
    {
        // restore original object state
        if (_cachedCopy != null)
        {
            First = _cachedCopy._first;
            Last = _cachedCopy._last;
            Image = _cachedCopy._image;
            Gender = _cachedCopy._gender;
        }

        // clear cached data
        _cachedCopy = null;

        // ensure edit mode flag is unset
        IsInEditMode = false;
    }

    public void EndEdit()
    {
        // clear cached data
        _cachedCopy = null;

        // ensure edit mode flag is unset
        IsInEditMode = false;
    }

    private bool _isInEditMode = false;
    public bool IsInEditMode
    {
        get { return _isInEditMode; }
        private set
        {
            if (_isInEditMode != value)
            {
                _isInEditMode = value;
                RaisePropertyChanged("IsInEditMode");
            }
        }
    }

    #endregion

Download the Sample

You can download the complete sample for this post to see the IEditableObject and IEditableCollectionView interfaces in action. When you run the sample, simply double-click an item (or press F2) to enter edit mode.

If you do not wish to commit your changes, press Escape. If you do wish to commit your changes, press Enter or simply select another character. When the changes are committed, you will notice that the item immediately moves to its proper location within the view.

Is IEditableObject Absolutely Required?

You posed the question, “What would you suggest I do if I have a collection of a type that I don’t know about at compile time?”

First, I would advise you to avoid that situation if at all possible. The model-view-viewmodel pattern typically involves wrapping or replicating items (and collections) of known types within observable classes (classes that provide change notifications like INotifyPropertyChanged and INotifyCollectionChanged) and adding additional interfaces (like IEditableObject) to either the data model objects or the viewmodel objects to allow them to play nicely with the view. That is always my preferred approach.

Having said that, there are certainly times when you may not have the option of modifying the entity within your collection. If you simply cannot add the IEditableObject interface to the data model or viewmodel class, you needn’t fret. The IEditableCollectionView interface is still your friend (as long as you are targeting .NET 3.5 SP1, of course). You won’t get all of the transactional goodness of IEditableObject, but you can still call EditItem() followed by CommitEdit() to update the view’s notion of a specific item.

Consider the earlier example where the characters were not correctly sorted or grouped after changing Bart’s name and gender. It turns out that you can simply add the lines below to cause that specific item to be moved to the correct location within the view:

    Character bart = lb.Items[0] as Character;
    bart.First = "Mandy";
    bart.Gender = Gender.Female;
    (lb.Items as IEditableCollectionView).EditItem(bart);
    (lb.Items as IEditableCollectionView).CommitEdit();

Voîla! There is no longer a need to explicitly refresh the entire view!

Order now and receive these bonus gifts!

The downloadable sample included with this post covers the specific questions posed by Patient-X, but there is more to IEditableCollectionView. It also provides a convenient way to add and commit new items to the source collection. You can even use it to remove existing items from the source collection. By leveraging members of the IEditableCollectionView interface for such changes, you can ensure that your view of the collection will remain accurate with respect to grouping, sorting, and filtering.

To see some of the other features of IEditableCollectionView, check out Vincent Sibal’s introduction to IEditableCollectionView, He also includes a nice code sample with his post.

Cheers,
Dr. WPF

P.S. For anyone who is hoping to get a published response to a WPF question, you should note (as Patient-X has) that the doctor is easily manipulated by wordsmithery. If you use lots of obscure terms like serein and hey rube, there is a much greater chance you will receive a public response, as it appeals to my invented persona’s inflated sense of perspicacity! 😉

ItemsControl: 'C' is for Collection

Monday, November 5th, 2007

The series continues…

An ItemsControl would be nothing without its collection of Items. In this post, we investigate the “Items” of an ItemsControl, looking at each of the following areas:

If I were rating the technical level of each post in this series, I would put this particular post somewhere in the range of moderate to advanced (but still very approachable :)).

The Items Collection (a.k.a, the ItemCollection)

The “Items” property of an ItemsControl provides access to a collection of objects, or data items, that make up the logical content of the control. The type of this property is ItemCollection. (I will use the terms “Items collection” and “ItemCollection” interchangeably.) The “Type” of each item within the Items collection is Object. So literally any CLR object can be added to an ItemCollection.

We will look at the ItemCollection class, itself, in more detail momentarily, but first, there are a couple of things to note about the Items property declaration on ItemsControl.

1) The Items property is a read-only CLR property.

This means that the collection exposed via the Items property must be instantiated by the control itself. In fact, the ItemCollection class does not even provide a public constructor.

2) The Items property is not backed by a dependency property.

This means that you cannot set a binding directly on the Items property. However, you can definitely bind an ItemsControl to a collection of items. We will look at how this works shortly, but before we do, we should look at the simpler, non-databound (or direct) scenario…

ItemCollection Modes: Direct and ItemsSource

Although the Items property is read only, the provided collection is not necessarily read only. In fact, in earlier posts, we’ve already seen that you can directly add items to an ItemsControl:

<ListBox>
  <sys:String>Item 1</sys:String>
  <sys:String>Item 2</sys:String>
  <sys:String>Item 3</sys:String>
</ListBox>

Because items are added directly to the ListBox, this is an example of using an ItemCollection in “direct mode”. This is by far the simplest mode to use conceptually. In direct mode, the ItemCollection class works exactly like every other .NET collection. You can directly access all of the expected members of an indexed collection: Add(), Insert(), Remove(), RemoveAt(), IndexOf(), Items[index], Count, etc.

The other mode for an ItemCollection is called “ItemsSource mode”. In ItemsSource mode, the items in the ItemCollection correspond to items in a source collection. That source collection is specified via a separate property on the ItemsControl that is appropriately named “ItemsSource”.

The following shows a typical scenario of an ItemsControl using ItemsSource mode:

<ListView ItemsSource="{Binding Path=Characters}">
  <ListView.View>
    <GridView>
      <GridViewColumn Width="100"
        DisplayMemberBinding="{Binding Last}"
        Header="Last Name" />
      <GridViewColumn Width="100"
        DisplayMemberBinding="{Binding First}"
        Header="First Name" />
      <GridViewColumn Width="60"
        DisplayMemberBinding="{Binding Gender}"
        Header="Gender" />
    </GridView>
  </ListView.View>
</ListView>

The ItemsSource property is a dependency property of type IEnumerable. This tells us two important things:

1) The source collection can be any enumerable collection.

2) The ItemsSource property can be established using a binding.

As such, it is the ItemsSource property (in conjunction with the ItemsSource mode of an ItemCollection) that enables an ItemsControl to be databound to a collection.

Sidenote: Although you will most often see the ItemsSource property of an ItemsControl set via a binding, there is no reason that the ItemsSource property cannot be directly set to an enumerable collection, as shown here:

<ListBox ItemsSource="{StaticResource Characters}" />

The Modes are Mutually Exclusive

It should be noted that direct mode and ItemsSource mode are mutually exclusive. An ItemCollection is either in direct mode or in ItemsSource mode, but never both.

Once Items have been explicitly added to the Items collection, it is in direct mode. A subsequent attempt to set the ItemsSource property after entering direct mode will result in an exception.

Similarly, once the ItemsSource property has been set, the Items collection is in ItemsSource mode. A subsequent attempt to directly modify the Items collection (using Add(), Insert(), Remove(), etc) will result in an exception.

The only way to change modes at runtime is to either 1) clear the Items collection via the Clear method (if in direct mode) prior to setting the ItemsSource property, or 2) set the ItemsSource property to null (if in ItemsSource mode) prior to calling the direct access methods of ItemCollection.

Observable Collections Support Dynamic Updates

As noted earlier, in direct mode, changes to the Items collection are made through direct access methods of the ItemCollection class. Any such direct changes made at runtime will cause the visuals to be updated immediately.

But what about dynamic collection changes in ItemsSource mode? How could the Items collection possibly know about changes to the source collection?

The answer is that the ItemCollection cannot know about any such changes unless the source collection chooses to announce those changes by providing change notifications. The way a source collection does this is by fully implementing and supporting the INotifyCollectionChanged interface. Any collection that provides these change notifications is said to be observable.

Dynamic changes to an observable collection will be immediately reflected in the Items collection of any ItemsControl that is bound to the collection. Consequently, these changes will be immediately reflected in the user interface.

The INotifyCollectionChanged interface is not super complex, but ensuring proper implementation does place an extra burden on the source collection. If developers had to implement this interface anytime they wanted to bind to a collection, it would be a huge inconvenience. Luckily, the .NET framework provides a very handy generic template class called ObservableCollection<T>. By creating an instance of this class, you automatically get all of the change notifications without having to do any extra work.

Typically, you will see a collection class derive from ObservableCollection<T>, to create a strongly typed collection, as follows:

    public class StringCollection : ObservableCollection<string>
    {
    }

Any instance of this StringCollection class is fully observable and will serve well as the ItemsSource of an ItemsControl. It can be used exactly like an instance of Collection<string>.

So what if the collection is not observable? Can it still serve as an ItemsSource?

Absolutely. As noted earlier, any enumerable collection can serve as the source of an Items collection. The only caveat is that the Items collection will not be updated dynamically if the source collection changes at runtime. Rather, the collection will be enumerated once and its members will be added to the Items collection when the ItemsSource property is first established. Thereafter, if you want the Items collection to be updated, you must explicitly call the Refresh() method of ItemCollection.

CollectionView: “The Great Equalizer”

If you’ve worked with ItemsControl much, you probably know that sorting, grouping, and filtering are supported via the CollectionView class. This class also supports the notion of currency, which means a CollectionView maintains a current item pointer that can be accessed and moved using methods on the CollectionView.

Every enumerable collection in WPF has a default view. The collection may have multiple other views, each with its own sorting, grouping, and filtering parameters. A common way to establish a view of a collection in markup is to leverage the CollectionViewSource class, as shown here:

<CollectionViewSource x:Key="characterView"
    Source="{StaticResource Characters} ">
  <CollectionViewSource.SortDescriptions>
    <componentModel:SortDescription PropertyName="First" />
  </CollectionViewSource.SortDescriptions>
  <CollectionViewSource.GroupDescriptions>
    <dat:PropertyGroupDescription PropertyName="Last" />
  </CollectionViewSource.GroupDescriptions>
</CollectionViewSource>

This CollectionViewSource can then be specified as the ItemsSource of an ItemsControl, thereby causing its associated view of the collection to serve as the CollectionView for the control.

“But Dad, I don’t WANT a CollectionView!”

“I didn’t ask what you WANT… As long as you’re living under my roof, you’ll use a CollectionView!”

With WPF, sometimes it’s not as much about what you want, as it is about what the framework needs. The CollectionView class is a classic example. When it comes to binding controls to a collection of data items, the framework needs a way to treat all collections in a consistent manner.

Unfortunately, not all enumerable collections were created equal. For example, IList provides direct index-based access to items, whereas IEnumerable requires that you enumerate all items starting from the beginning of the collection until you come to the index you care about. For another example, consider a collection class that supports the INotifyCollectionChanged interface to provide collection change notifications versus a simple Collection<T> class that provides no such notifications.

The framework architects wanted to support binding to as many different types of collections as possible. But imagine how ugly the code for the ItemsControl class would be if it had to account for differences among collection types with conditional code blocks… if it’s an observable collection, do this, or if it’s an IList, do this, or if it’s an IEnumerable, do this, etc.

Enter the CollectionView class…

To deal with this challenge of disparate collections, WPF introduces the CollectionView class to serve as the great equalizer of enumerable collections. It is the CollectionView class that internally looks at a collection’s supported interfaces and determines how best to deal with the collection. It then surfaces a view of the collection through a well-defined set of properties, methods, and events. Essentially, it allows all collections to be treated by the ItemsControl class as equals.

So whether or not you care about currency, grouping, sorting, filtering, change notifications, etc., the Items collection of an ItemsControl is always maintained internally using a CollectionView. In fact, the ItemCollection class is a CollectionView.

Although true, that last statement is a little misleading since really, ItemCollection is just a wrapper class for an internal CollectionView member. The type of the internal CollectionView is determined by the type of the source collection and the mode of the ItemCollection. In Direct mode, it is always of type InnerItemCollectionView (an internal class designed specifically for direct mode views). In ItemsSource mode, it will be of type CollectionView for an IEnumerable source, ListCollectionView for an IList source, or BindingListCollectionView for an IBindingList or IBindingListView source.

So you’re observable… Who cares?

CollectionView does. We’ve already noted that dynamic changes to observable collections are immediately reflected in the Items collection. It is the CollectionView class that actually listens to the events raised by the collection. So if you’ve ever wondered exactly who is monitoring these events, get a life! Sorry… I meant to say, it’s CollectionView. Now you know.

Performance Considerations around Bound Collections

Keeping in mind that CollectionView serves as the great equalizer of collections, we should look at some performance considerations around binding to collections. We’ve already acknowledged that not all collections support the same features. Often, CollectionView must perform extra work to support its common interface for collections.

One of the major features provided by CollectionView is indexing for an enumerable collection. That is, CollectionView provides direct access to members of the collection by an integer-based index. This means it must support properties like this[int index] and Count, as well as methods like Contains() and IndexOf().

If the source collection already supports indexing, you will see much better performance when binding to the collection. This means that the best candidates for a source collection are those that support the IList interface. It should be noted that ObservableCollection<T> implements IList, so it’s a great choice.

If the source collection does not support index-based access (ICollection or IEnumerable, for example), then CollectionView must do a lot more work to surface the view as an indexed collection. In order to support a property like Count, it may be necessary to enumerate the entire collection. And some methods like Contains(), IndexOf(), and GetItemAt() can be super expensive, since the performance of the algorithm to support these operations is directly proportional to the size of the collection.

So the key perf takeaway is that the source collection should support IList whenever possible.

Items and the Element Trees

The items within the Items collection make up the logical children of the ItemsControl. They are said to be members of the logical tree. For a HeaderedItemsControl, the headers associated with each item will also be logical children of the ItemsControl. (Btw, if you’re not sure what a HeaderedItemsControl is, you should revisit The ICIQ Test and spend a little more time exploring the tooltips after receiving your score.)

If the items in the Items collection happen to be visuals, then they will also be members of the visual tree. If they are not visuals, they will instead be represented visually using an inflated template of visuals. Since the template represents data items, it is called a DataTemplate. For more on that, please tune in for the next episode in this series… ‘D’ is for DataTemplate.