Implementing a tilt effect behavior for UWP with Windows Composition

Last year a new UWP API surfaced: Windows.UI.Composition. It’s a framework agnostic composition library that can be used on its own, to enrich your existing XAML layouts or to entirely replace the default Storyboard implementation, among other uses. But it’s not limited to manipulating UI elements or animating them – you can even apply Direct2D effects/shaders (instantiated via the awesome Win2D library) to existing XAML elements in real time.

This post will be a brief explanation of a real world usage of the Windows Composition features: implementing a behavior that, when attached to a XAML control, makes it “tilt” when tapped/clicked, just like Windows Phone used for interactive UI elements.

Approach

The idea is to subclass a Behavior and, when it is attached to a control (via the OnAttached override), obtain a reference to the Windows Composition Visual element of that control. Also, we will subscribe to the relevant Pointer* events to check when the user is interacting and apply or reset the tilt effect.

Here is how our behavior is going to react to each input event:

  • PointerPressed: apply the tilt effect.
  • PointerMoved: if the touch/mouse is currently pressed (PointerRoutedEventArgs.Point.IsInContact is true), apply the tilt effect; reset it otherwise.
  • PointerReleased, PointerCanceled, PointerExited: reset the tilt effect.

Finally, the tilt effect will consist on applying a rotation to the Visual element using its center as the pivot point, and with a rotation axis such that the plane of the control “looks” at the touch/mouse position.

This is how we set the center point of the Visual – since it’s going to be in coordinates relative to the control, we just multiply both the width and the height retrieved from RenderSize by half. The Z offset will make it look like as if it’s being pressed and sent to the background:

[code language=”csharp”]
// Set a center point for rotating the Visual.
// The Z value adds a bit of depth movement.
this.elementVisual.CenterPoint = new Vector3((float)(this.uiElement.RenderSize.Width * 0.5f), (float)(this.uiElement.RenderSize.Height * 0.5f), -10.0f);
[/code]

Now, we get the contact point (again in coordinates relative to the control) and use it to calculate the offset vector pointing from the control’s center to the point of contact, and then normalize it:

[code language=”csharp”]
// Get the contact point of the pointer, in coordinates relative to the Visual.
var contactPoint = e.GetCurrentPoint(uiElement).Position;

// Obtain an offset vector from the center and normalize it.
var contactVector = new Vector3((float)contactPoint.X, (float)contactPoint.Y, 0.0f) – this.elementVisual.CenterPoint;
contactVector = Vector3.Normalize(contactVector);
[/code]

The last step is setting both the rotation axis and the amount of rotation around it, in this case in degrees:

[code language=”csharp”]
// Swap vector coordinates so they point to the correct corner and the final rotation is correct.
this.elementVisual.RotationAxis = new Vector3(contactVector.Y, -contactVector.X, 0.0f);

// Rotate by a set amount of degrees.
this.elementVisual.RotationAngleInDegrees = 20.0f;
[/code]

When we want to reset the tilt effect, we just set its rotation to 0:

[code language=”csharp”]
this.elementVisual.RotationAngleInDegrees = 0.0f;
[/code]

Caveats

This has been done as a way of learning the basic bits of Windows Composition, and while trying to mimic the general behaviour of the old tilt effect, it doesn’t do it 100% accurately. For example, tapping on the center of the control should apply little to no rotation, and just send it to the back; also, the scaling looks a bit weird on too wide or too tall controls. And the current touch detection implementation only fires when the cursor/touch point is hitting the text of a TextBlock control – it should work on its entire bounding box. However, if it suits your needs – feel free to use it on your projects!

What are you waiting for? Grab the source code on its GitHub repository.

Fixing DataContractSerializer issues in builds compiled with .NET Native

With UWP apps having mandatory .NET Native compilation before uploading to the Store, a new kind of issues have started to pop up: those caused by types and methods not processed (or stripped) by the native compilation process.

While working on a pretty complex app I started experiencing this: everything worked good on Debug and Release builds that had .NET Native compilation turned off, but the moment it was switched on, the app started to experience weird crashes and exceptions raised in parts of the code that used to work without any flaws; the majority of them were related to data serialization, especially of types that relied on DataContractAttribute / DataContractSerializer.

While Microsoft published a list of instructions for migrating existing codebases to .NET Native and even it has a section explaining all issues that can happen with the different types of serialization, if you skip any of the types while updating the runtime directives file, tracking down what is happening can be a bit frustrating.

In this case, I was experiencing InvalidDataContractExceptions followed by the typical .NET Native call stack with no symbols:

Serialization exception: System.Runtime.Serialization.InvalidDataContractException: SerializationCodeIsMissingForType. For more information, visit http://go.microsoft.com/fwlink/?LinkId=623485
   at App!<BaseAddress>+0xb51dc8
   at App!<BaseAddress>+0xb525aa
   at App!<BaseAddress>+0x1384c9c
   at App!<BaseAddress>+0x13846a0
   at App!<BaseAddress>+0xb420fc
   at App!<BaseAddress>+0xb4203b

This will happen in a code block that is using DataContractSerializer. So, get the type of the variable being serialized and add it to the default runtime directives file, which should be part of your project and called Default.rd.xml under the Application XML node:

<!-- Make all members of a type visible to .NET Native -->
<Type Name="App.Models.MyModel" DataContractSerializer="Required All" />

<!-- Make all members of all types inside the namespace visible to .NET Native -->
<Namespace Name="App.Data.Models" DataContractSerializer="Required All" />

This tells .NET Native to include all members needed for serialization through DataContractSerializer so they can be properly accessed at runtime, fixing all issues that were present on the app. Please note that if you are using DataContractJsonSerializer, XmlSerializer or other third party serializers like the Newtonsoft JSON one, the changes to the Default.rd.xml file will be slightly different.

AppRaisin promotion works, and you should start using it now

AppRaisin is a new Windows 10 app from the same guys that run AdDuplex, and it’s meant to fill the niche that the now defunct Nokia App Social left when it closed down back in 2015. It’s meant as a discovery platform where users send links to newly launched (or recently updated) UWP or Windows Phone apps and then they are voted (“raised”) by the community. The most popular ones raise to the top of the list so they have more visibility, and you usually can see yesterday’s best apps in between today’s raising ones. Oh, and it’s entirely free.

My experience with it has been extremely positive so far. Everything begins back in November 2015, when I attented the Submit It hackathon in London and made a small UWP app: Universal Battery Tile. My idea behind it was to ship a really simple first version and then iterate with new features from time to time; also, I would try to focus on monetization and marketing too, making some of the new features available only to paid users and trying to promote it enough when it reached a more complete state.

The app was soft launched during the hackathon, and no promotion was done at all except for including AdDuplex banners. Some days later, a Russian site reviewed it, which provided a small bump in downloads. And at the beginning of January, with a bigger update that changed the UI by adding a hamburger menu, I decided to try luck and send it as an “app discovery” to AppRaisin. The results were better than expected.

AppRaisin submission for Universal Battery Tile
AppRaisin submission for Universal Battery Tile

The news item was submitted to AppRaisin on the 6th of January, and it had 24 raises that day (with some more coming later). It was at the top of the discovery queue for some time, until more popular items took its spot. This brought a good amount of downloads.

Dev Center download stats
Dev Center download stats

As you can see from the graph above, the app got ~190 downloads in a single day, almost 5 times more than the 40 that it got by being reviewed. And with the extra downloads on the following days for being still discoverable, it amounted a total of 400 or so. Not all of them ended being final or recurring users, though, as you can see from the Azure Application Insights graph below; still, the average daily user base grew from 100 to a whooping 250.

Azure Application Insights user stats
Azure Application Insights user stats

And the best part? AppRaisin also automatically applies a campaign tracking tag to submissions, so you can know afterwards how many conversions your app had thanks to promoting it (although it seems to be a bit broken on the Dev Center side, since the picture below shows only 5 IAP conversions, but the reality is that I got 17 purchases during those days – an awesome 4% conversion ratio that doubles the usual 2%).

Dev Center marketing campaign stats
Dev Center marketing campaign stats

So, what are you waiting for? It’s free, it takes literally 5 minutes to link your app and write a short description about it or the features on the latest update, and there is a huge (and growing) user base that checks AppRaisin for new apps.