One of the coolest things in every new developer platform is the challenge to master the entire framework in a way that enables you to create high quality, greatly optimized controls that behave in exactly the same way a user would expect to. Yesterday Microsoft announced that more than 300 000 developers have already downloaded the WP7 Developer Tools Beta. Based entirely on Silverlight, phone development has never been easier and more fun than in the Windows Phone 7 environment.
With these series of blogs I want to reveal some tricky moments in developing a simple DatePicker control for WP7. The control should mimic the one described in the public Design Guidelines:
At first sight the control should be pretty easy to implement. We have a line of three buttons aligned vertically; when a button is clicked, we display a ListBox which allows a specific date component (Day, Month or Year) to be chosen. Digging deeper reveals several challenges:
The ListBox in WP7 uses the IList interface to communicate with its assigned data source. Only three methods from this interface are used, namely:
So, if we provide a custom IList implementation that knows how to implement these three methods we can have our data virtualized. Let’s have a look in this pretty simple virtualized data source:
VirtualizedListSource<T> : IList
.virtualCount = virtualCount;
/// Gets or sets the count of virtual items.
.virtualCount = value;
/// Gets the count of this data source.
/// Gets the data item at the specified index.
/// <param name="index"></param>
VirtualizedDataItem<T> item =
item.Index = index;
VirtualizedDataItem<T> item = value
EventHandler<VirtualizedDataItemEventArgs<T>> eh =
VirtualizedDataItemEventArgs<T> args =
item = args.Item;
I have intentionally skipped the rest IList implementation as all other methods are not needed and they are not the focus of this post. Whenever an item at a specified index is requested, we raise the DataItemNeeded event, and then check whether a user-defined item is supplied and if not we create a default item instance. Using the provided implementation we may easily create a data source for the “Year” ListBox:
YearsDataSource : VirtualizedListSource<DateTime>
//consider that lists are zero-based
DateTime(index, 1, 1));
An important thing to note here is the fact that we need an ItemTemplate specified so that the ListBox uses UI virtualization. Otherwise the entire exercise will be useless.
Now that we have our virtualized data we can come up with a very elegant and simple implementation of the “infinite ListBox” feature. The idea is that we can specify a fairly large virtual item count and a number of logical items (for example the “Month” ListBox will have 12). We can then override the GetItemAt method of our VirtualizedListSource class, translate the desired index within the range of logical items and return the logical item at that index. Here is the sample data source:
WheelDataSource<T> : VirtualizedListSource<T>
Having let’s say 1 million virtual items and scrolling the ListBox to the middle will give the user the perception of an endless looping ListBox – he can scroll up and down by a total of 500 000 items in each direction.
I want to dig a bit deeper here. One may wonder why I am not using my own custom panel implementation that applies UI virtualization rather than playing with the data source of the ListBox. There are some limitations in the underlying framework that implicitly force you to use only primitive controls that are already present. One limitation is the sealed classes. For example you may not create your own custom ScrollViewer implementation by simply deriving from the base one as it is marked with the “sealed” keyword. So you have two options here: a) Use the built-in one and b) Create your own one entirely from scratch, deriving from ContentControl. While creating your own implementation always has its pros, it also has its cons, especially in the context of Windows Phone. Consider things like handling manipulation events, multi-touch, animations and scrolling as well as internal interfaces that update some other internal stuff which in turn updates more internal properties and calls internal methods. Put simply creating a custom data-source that exploits the built-in ListBox seemed the easiest and simplest solution (especially as a start-up :)).
Well, that’s all for now. In the next post I will cover creating a DateListBox which has a SelectedDate property and may be used to select a Date component – Day, Month or Year. Stay tuned.
Copyright © 2017, Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
Progress, Telerik, and certain product names used herein are trademarks or registered trademarks of Progress Software Corporation and/or one of its subsidiaries or affiliates in the U.S. and/or other countries. See Trademarks or appropriate markings.