I added LayoutAwarePage
to my project and modified MainPage
to use it as a superclass and hey-presto, my snapped view worked! Here is the list snapped next to an image of some beautiful rolling countryside, courtesy of the Bing app:
So far the view models have been ported and the application UI has been tailored for Windows 8. It’s time to get started on porting the gestures that made this such an interesting to-do list application in the first place.
The Windows Phone application described in my previous article uses the concept of an interaction, as defined by the IInteraction
interface, which attached event handlers to each of the items within the list. The InteractionManager
coordinates the various interactions to ensure that only one is active at any one time. These concepts port just fine to the Windows 8 version of the app.
I took the same approach as I did with the view models, add the Windows Phone classes to the Windows 8 project then start resolving compilation issues. This time the changes required to port the code were much more numerous:
- Lots of namespace changes!
- The manipulation event arguments are different
ManipulationCompletedEventArgs => ManipulationCompletedRoutedEventArgs
(and the same applies for Started, Delta and other events). - The event arguments are different
e.TotalManipulation => e.Cumulative
- The e.FinalVelocities property is not present, making it hard to create interactions where you manage your own inertia / momentum
- e.DeltaManipulation => e.Delta
- The animation easing property changes type,
IEasingFunction => EasingFunctionBase
- Storyboard target properties are of type string rather than
PropertyPath
instances. - The
LayoutUpdated
event is of type EventHandler<object>
rather than simply EventHandler
.
That’s quite a list of changes required to the code to get it compile. Frustratingly there is nothing fundamentally different in terms of what Windows 8 can and cannot do when compared to Windows Phone. The API is just ever so slightly different!
Anyhow I’ve already climbed on my soapbox once already, for now I’ll push it to one side and just get on with making this thing work.
With the above changes I was able to make the SwipeInteraction
code compile, adding it to the MainPage.xaml
via the InteractionManager
… and when I ran the application, it did absolutely nothing!
With a bit of poking around on the forums and API documentation I discovered that the way Windows 8 Store Apps handle interactions is very different to Windows Phone. You can attach manipulation events to any UIElement
however, these are only fired if you also set the ManipulationMode
on the element. The manipulation mode enumeration provides values that allow you to constrain the type of interaction that the element participates in, e.g. TranslateX
, TranslateY
. Interestingly you can also specify whether the manipulation should include inertia with values such as TranslateIntertia
or RotateIntertia
, when inertia is applied delta events continue to fire event after the user has stopped manipulating. The various values can be ORed together for any element.
In order to make the SwipeInteraction
work I set the ManipulationMode
property of the elements that render each to-do item. Unfortunately, this has the rather undesirable side-effect that the list no longer scrolls. The ScrollViewer
has a ‘special’ ManipulationMode
of System that provides a smooth scrolling experience, no doubt this is similar to Windows Phone Mango where scrolling was pushed to a separate thread. Unfortunately Windows 8 ManipulationModel.System
does not cooperate with child elements that have ManipulationMode
of anything other than None. To put it bluntly, you cannot handle manipulation events on any element within a ScrollViewer without breaking scrolling.
This was a bit of a blow to my application!
The workaround that I came up with was to add little ‘thumb’ controls to each item in the to-do list. These are user controls which are located to the left and right edges of each item, and accept the manipulations required to perform the swipe gestures:
<DataTemplate x:Key="toDoItemTemplate">
<Border Height="55" x:Name="todoItem">
<Grid Margin="2"
Background="{Binding Path=Color, Converter={StaticResource ColorToBrushConverter}}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
-->
<local:ThumbControl Loaded="Border_Loaded"
Width="40" Height="55" ManipulationMode="All" />
<local:ThumbControl Loaded="Border_Loaded"
Width="40" Height="55" ManipulationMode="All"
Grid.Column="2"/>
-->
<TextBlock Text="{Binding Text, Mode=TwoWay}"
FontSize="25" TextTrimming="WordEllipsis"
Foreground="White"
VerticalAlignment="Center"
Grid.Column="1"/>
<Line Visibility="{Binding Path=Completed, Converter={StaticResource BoolToVisibilityConverter}}"
X1="0" Y1="0" X2="1" Y2="0"
Stretch="UniformToFill"
Stroke="White" StrokeThickness="2"
Margin="8,5,8,0"
Grid.Column="1"/>
</Grid>
</Border>
</DataTemplate>
You can see the ‘thumb’ controls in the image below:
With this in place, the application accepts the swipe-to-the-right to complete and swipe-to-the-left to delete gestures. Although the user must of course swipe from one of the ‘thumbs’, and must scroll using the central region of the to-do item.
With more code wrangling I was also able to add the gesture which allows you to drag re-order the list. The main issue I hit this time was that the Windows 8 WriteableBitmap
does not have a constructor that takes a FrameworkElement
as an argument. With Windows Phone this is a very popular technique that can be used to ‘clone’ part of the UI in order to perform some advanced graphical effect. With Windows 8 I had to make a few compromises that resulted in z-index issues, i.e. the dragged item is not always on top of the items you are dragging it over.
The image below shows an item mid-drag:
The Windows Phone application had a couple of other novel interactions, the first is a pull-to-add-new interaction which I found that I was unable to implement in Windows 8. This is no great surprise, the Windows Phone version was a bit of a hack, relying on mouse events and probing the ScrollViewer
Content to inspect the transforms that the framework had applied. The second was a pinch-to-add-new gesture, my feeling is that the ManipulationMode
restrictions that Windows 8 impose would make this gesture, while technically possible, just too uncomfortable for the user to work with.
OK, time to report some good new features that have emerged with Windows 8 – Transitions. Actually, I’ll re-phrase that, they are a great new feature!
With Windows Phone I found it a little frustrating that the applications that shipped with the OS were more fast and fluid than those written by my fellow Silverlight developers. With the OS apps (email, calendar etc …) lists swishes and transitioned, items tilted and search results flowed. Because of this I embarked on a seven part blog series called “Metro In Motion”, where I showed how to mimic the fluid animations found in the OS apps. The series proved to be pretty popular!
Windows 8 has many of the metro-style transitions built directly into the framework. You can set the Transitions property of any element to values such as EntranceThemeTransition
, AddDeleteThemeTransition
etc … and the elements will automatically be animated as they appear, are deleted etc …
Even more powerful is the ChildTransitions
property of Panel, which applied the specified transitions to its child element, firing them with a slight delay as each item is added. This produces an elegant and fluid interface without the need to write any code. I think this is a great new feature and something I blogged about in detail when the CTP was released.
It’s hard to capture these transitions with a simple screenshot, but here is the entrance transition for the application:
I’d thoroughly encourage you to familiarize yourself with transitions and use them in your own apps.
Time to add some Windows 8 specific features …
Whilst Windows Phone has live tile support, Windows 8 takes this onto a whole new level. Live tiles (and secondary tiles) can display a wide range of information based on a number of templates which are part of the framework. Updating an app’s live tile is as simple as sending an XML tile notification via the TileUpdateManager
.
The documentation provides a great overview of all the tile notification types together with their XML. Unfortunately the SDK samples over complicate things a little, providing an abstraction layer on top of these XML messages making them easier to create. My feeling is, once again, that SDK samples should be simple and concise. If the sample authors feel that the framework is not simple enough to use and end up writing abstractions, the SDK itself needs to be simplified!
Sending an XML message that updated the tile state really isn’t that difficult. I updated the ToDoListViewModel
to detect changes in its own state and notify the live tile using the following code:
private void UpdateTileStatus()
{
XmlDocument tileXml = TileUpdateManager.GetTemplateContent(TileTemplateType.TileWideBlockAndText01);
int index = 0;
foreach(ToDoItem item in _todoItems.Take(4))
{
SetElementText(tileXml, index++, item.Text);
}
SetElementText(tileXml, 4, _todoItems.Where(t => !t.Completed).Count().ToString());
SetElementText(tileXml, 5, "Left to-do");
TileUpdateManager.CreateTileUpdaterForApplication().Update(new TileNotification(tileXml));
}
private void SetElementText(XmlDocument doc, int index, string text)
{
var element = (XmlElement)doc.GetElementsByTagName("text")[index];
element.AppendChild(doc.CreateTextNode(text));
}
This generates XML of the following format:
<tile>
<visual>
<binding template="TileWideBlockAndText01">
<text id="1">Feed the cat</text>
<text id="2">Buy eggs</text>
<text id="3">Pack bags for the MVP conference</text>
<text id="4">Rule the web</text>
<text id="5">18</text>
<text id="6">Left to-do</text>
</binding>
</visual>
</tile>
The only minor issue I found here is that the simulator does not support live tiles, to test the above code you have to run the application on your ‘local machine’. Other than that, live tiles are a breeze to use. The screen shot below shows the app live tile which lists the four top-most items in the to-do list together with the number of items left to complete:
Windows 8 has a charms bar which collects together features and functions that are common across most applications. One contract that it makes sense for the to-do application to implement is search. Handling search input is as easy as handling the QuerySubmitted
event as shown below:
protected override void OnWindowCreated(WindowCreatedEventArgs args)
{
SearchPane.GetForCurrentView().QuerySubmitted += OnQuerySubmitted;
}
In the to-do list application I handled this at the application-level, sending the search input to the MainPage using a static singleton (gasp!).
I added a SearchText
property to the view model and modified the Items property which exposes the collection of to-do items to filter the collection is the SearchText
property has been set:
public ObservableCollectionEx<ToDoItem> Items
{
get
{
if (string.IsNullOrEmpty(_searchText))
{
return _todoItems;
}
else
{
return new ObservableCollectionEx<ToDoItem>(
_todoItems.Where(i => i.Text.ToLowerInvariant().Contains(_searchText.ToLowerInvariant())));
}
}
}
That’s pretty much all you need to handle basic search operations: