Monthly Archives: February 2016

GrovePi, Raspberry Pi, and the Universal Windows Platform: better together

Blinky on Steroids

This article introduces a C# and XAML UWP app that has the ambition to make you feel comfortable with Windows IoT. We’ll make a LED blink, measure the temperature, detect motion, and do some other internet-of-things like that. This means that you need extra hardware to fully enjoy it: a Raspberry Pi computer running Windows 10 and connected to a monitor, a GrovePi board, and of some Grove sensors from a typical starter kit.

The Universal Windows Platform app that is presented here, allows you to execute tests against the GrovePi board that is hooked to the Raspberry Pi computer, but -more important- against a range of sensors and actuators that are plugged into that board. The app also contains a project that hooks sensors and C# code together into a burglar alert.

The list of supported sensors includes:

    • LED (a.k.a. Blinky)
    • Button 
    • Light Sensor
    • Passive Infrared Motion Sensor
    • Rotary Angle Sensor (knob) 
    • Temperature Sensor
    • Vibration Motor
    • LED Bar

Here’s a picture of the app and some of the hardware in action:

blinky

That picture brings me to the following quiz question: “How many Windows 10 devices does it take to make a picture of a blinking LED?

In case, the answer was 3:

  • The app was written on a Windows 10 development machine, and then
  • deployed to a Windows 10 Raspberry Pi, and finally
  • the picture was taken with a Windows 10 Lumia 950.

Getting started with Windows 10 IoT

In February 2015 Microsoft announced that Windows 10 was coming to the Raspberry Pi. Very soon, Windows 10 Internet-of-Things kits started to appear. Most of these looked (and still look) like this:

startkit

I can image that for a lot of software developers (the ones that are NOT writing device drivers) such a starter kit is out of their comfort zone, since it’s way too close to the bare metal. If you’re one of these developers: don’t worry. There are also IoT starter kits that look like this:

GrovePi for Raspberry Pi and Grove Sensors

What you see here is not only a Raspberry Pi computer, but also

  • a GrovePi board that you can connect to the Raspberry Pi and that exposes ports in which you can plug
  • a series of ready-for-use sensors and actuators,
  • all in pure Lego-style (well … almost: the picture does not show the connector cables).

Call it modular, call it service-oriented, call it component-based … it is clear that this approach is a lot closer to a developer’s eco-system. When you get your hands on such a kit, you may be more tempted to give it a try.

Configuring the hardware

It’s not the intention of this article to explain how to install Windows 10 on a Raspbery Pi and how to configure your development PC. Microsoft has excellent documentation on this right here.

In theory the GrovePi board itself does not need extra configuration, since it comes with its own built-in firmware. In practice, it is a relatively recent and fast evolving system, and some of the starter kits come with older versions of it. In order to support all sensors, you may need to upgrade the firmware from time to time. This is done from the Raspberry Pi. It can not be done when the Pi is running Windows 10, so you need to prepare an extra SD Card with Raspbian for Robots (which also contains an adapted version of the Scratch programming language, for your kids). There’s good documentation on all of this, and if you get stuck, the GrovePi forum moderators are always there to help you.

Connecting the sensors

The GrovePi board comes with a series of ports in which you can plug the sensors.

warningAlthough all ports look the same, it’s important to know that not every sensor will work on any port.

There are GrovePi-controlled analog as well as digital ports, and there are also serial ports and I2C ports that connect directly to the Raspberry Pi. All port characteristics are described right here.

warningIt’s also important to know that not every Grove sensor is already supported by the GrovePi board.

The company –Dexter Industries- produces more than 100 sensors, but they also produce several robots with exactly the same port layout. Not every sensor works on every robot. Here’s the official list of sensors that are currently supported by the GrovePi – that’s still more than 50.

The test bench app that I wrote supports a lot less sensors. It is limited by the sensors for which there is already GrovePi and C# support and that are available in this starter kit.

Before you deploy and run the app, you must connect the following sensors to the appropriate port:

  • LED in digital port 5
  • Temperature sensor in analog port 2
  • Light sensor in analog port 1
  • Rotary encoder in analog port 0
  • Push button in digital port 3
  • LEB Bar digital port 4
  • Motion sensor in digital port 2
  • Vibration motor in digital port 6
  • Infrared emitter in digital port 7
  • Infrared receiver in digital port 8

By the way, it’s best to connect the sensors before firing up the Raspberry Pi. Those stories saying that the Pi reboots when you plug a LED in it … are true.

Your board should look like this:

board

Talking C# to the GrovePi board

The pioneering library that allows you to communicate from C# with the GrovePi board lives here on GitHub. It contains the source code for the GrovePi for Windows IoT Nuget package:

GrovePiNuget

There are some forks available at Dexter Industries, Seeed Studio, and Exadon. These repositories are all extended with sample projects in C# and other languages, so they’re definitely worth a visit.

Recently, the NuGet package started to give some errors:

GrovePiNugetIssue

As a work around, I decided to uninstall the package, then add its core dll to the project and refer directly to it:

GrovePiNugetWorkaround

Alternatively, you could clone one of the source repositories and add the project to your Visual Studio solution.

Building the app

The sample app is a regular XAML-based UWP app and not a UI-less background task. As you see on the above screenshot, the project is MVVM-oriented. The Windows 10 IoT stack indeed supports the basic XAML and C# features that we’re used to on the PC, the tablet and the phone. If Notifications would work, I could even have reused the whole template that I currently use for this series of blog posts. As a matter of fact: most of the sample apps that I wrote this year, ran on the Raspberry Pi without any modification.

The GrovePi Test Bench

The main page of the sample app displays the list of connected sensors in a GridView. It allows you to start a test against each of them – simultaneously if you want. Each test takes about a minute. During the test, the sensor has a red border around it in the UI:

blinkyview

All sensors are represented by a ViewModel class that inherits from this one:

SensorBase

Here’s its code:

/// <summary>
/// Base class for testable GrovePi sensors.
/// </summary>
internal class SensorBase : ViewModelBase
{
    private string name;
    private string port;
    private string state;
    private bool isUnterTest;
    private string testDescription;

    public string Name
    {
        get { return name; }
        set { SetProperty(ref name, value); }
    }

    public string Port
    {
        get { return port; }
        set { SetProperty(ref port, value); }
    }

    public string State
    {
        get { return state; }
        set { SetProperty(ref state, value); }
    }

    public bool IsUnderTest
    {
        get { return isUnterTest; }
        set { SetProperty(ref isUnterTest, value); }
    }

    public string ImagePath { get; set; }

    public string TestDescription
    {
        get { return testDescription; }
        set { SetProperty(ref testDescription, value); }
    }

#pragma warning disable CS1998 
// Async method lacks 'await' operators and will run synchronously
    public virtual async Task Test()
    { }
#pragma warning restore CS1998

    public ICommand TestCommand
    {
        get { return new DelegateCommand(Test_Executed, Test_CanExecute); }
    }

    private bool Test_CanExecute()
    {
        return !IsUnderTest;
    }

    private async void Test_Executed()
    {
        await RunTheTest();
    }

    private async Task RunTheTest()
    {
        IsUnderTest = true;
        try
        {
            await Test();
        }
        catch (Exception ex)
        {
            State = ex.Message;
            Log.Error(this.Name + " - " + ex.Message);
        }

        IsUnderTest = false;
    }
}

When the app is started, we first check the board itself and retrieve its firmware version with some calls against the API in the GrovePi dll:

// Check the board.
var board = DeviceFactory.Build.GrovePi();
if (board == null)
{
    Message = "Sorry, your GrovePi board could not be detected.";
}
else
{
    try
    {
        Message = string.Format("Your GrovePi board is ready. 
	(Firmware version {0})", board.GetFirmwareVersion());
    }
    catch (Exception)
    {
        Message = "Your Grove board is ready.";
    }
}

Of course, every sensor has its own test. Here’s how to make the LED blink for a minute:

/// <summary>
/// Blinky.
/// </summary>
public override async Task Test()
{
    var blinky = DeviceFactory.Build.Led(Pin.DigitalPin5);
    if (blinky == null)
    {
        State = "Failed to intialize.";
        return;
    }

    for (int i = 0; i < 30; i++)
    {
        try
        {
            blinky.ChangeState(SensorStatus.On);
            State = "On";
        }
        catch (Exception ex)
        {
            Log.Error(this.Name + " - " + ex.Message);
        }

        await Task.Delay(TimeSpan.FromSeconds(1));

        try
        {
            blinky.ChangeState(SensorStatus.Off);
            State = "Off";
        }
        catch (Exception ex)
        {
            Log.Error(this.Name + " - " + ex.Message);
        }

        await Task.Delay(TimeSpan.FromSeconds(1));
    }

    State = String.Empty;
}

I’m pretty sure that you frowned a couple of times when looking at the amount of Try-Catch blocks and when looking at the content of these Catch blocks. Basically all exceptions are ignored in a true On-Error-Resume-Next style.

Allow me to defend this approach: the hardware that runs the app is pretty young and pretty inexpensive (it costs between 1% and 2% of a standard development laptop).

warningThe communications between the Raspberry Pi, the GrovePi, and the sensors fail very often, so you must wrap any API call in a Try block.

Writing a sensor test

The LED is a digital output sensor: you can programmatically turn it On of Off. All digital output sensors can be tested with exactly the same code. The test for the Vibration Motor (the buzzer in your cell phone) is identical to the previous code snippet.

Let’s take a look at the opposite: an analog input sensor. Here’s the code to read the value of  the light intensity sensor twice per second, during a minute:

public override async Task Test()
{
    var sensor = DeviceFactory.Build.LightSensor(Pin.AnalogPin1);
    if (sensor == null)
    {
        State = "Failed to intialize.";
        return;
    }

    for (int i = 0; i < 120; i++)
    {
        try
        {
            State = sensor.SensorValue().ToString();
        }
        catch (Exception ex)
        {
            Log.Error(this.Name + " - " + ex.Message);
        }

        await Task.Delay(TimeSpan.FromSeconds(.5));
    }

    State = String.Empty;
}

Again, most of the code is defensive exception handling, and again, this code is reusable for similar sensors like the temperature sensor and the rotary encoder.

While reading an analog value, you may want to apply some math to it. For the temperature sensor you probably want to translate the incoming value (which is between 0 and 1023) into your own unit measure. By default the temperature sensor API translates the raw input to the Metric system: you can directly read the value in °Celsius from the API. If you want to get the temperature in °Fahrenheit, just add an extension method.

A lot of currently ‘unsupported’ sensors can be easily read in the same way. It suffices to find out the algorithm to translate the value, by looking at the specs of the sensor, by reading sample code from another language, or by asking it in the forum. Here’s an example: a thread for the air quality sensor, leading from a forum question, to the specs and sample code.

Here’s an overview of the different sensor types and their relevant API calls to the GrovePi NuGet package:

Type Direction Examples GrovePi API calls
Analog Input Light sensor, temperature sensor, rotation angle sensor SensorValue()
Digital Input Button, motion sensor CurrentState
Analog Output LedBar, infrared emitter ?
Digital Output Led, vibration motor ChangeState(SensorStatus)

If the sensor API is not sufficient, then you can go one level deeper and call the GrovePi class directly. It comes with methods to specify the direction of a port (input or output) an then read or write to it, digital or analog:

IGrovePi

If you want to create your own implementation for a currently unsupported sensor, just create a viewmodel and hook it in the tree:

SensorViewModels

Also don’t forget to add the sensor in AddSensors() of MainPageViewModel or it won’t show up in the list.

[At the time of writing this article I’m still working on the tests against the Infrared receiver and the Infrared transmitter, since these are actually not yet officially GrovePi supported.]

Building a Burglar Alert

Now that all sensors are connected to the Raspberry Pi and testable, why not make a little IoT project with them?

The sample app contains a Burglar Alert page that reuses some of the viewmodels and data templates from the main page. It uses the motion sensor, the LED, and the buzzer. Here’s how it looks like:

burglarview

The process is always in one of the following states:

enum BurglarAlertState
{
    Sleeping,
    Active,
    MotionDetected,
    Alerting
}

When the alert is Active, we monitor the motion sensor. When motion was detected, we note the time, and upgrade the state to MotionDetected. The LED will start blinking. If there’s no motion anymore after 10 seconds, we consider it a false alert and go back to Active. If there is still motion however, we enter Alerting mode and the buzzer will vibrate until we set it to sleep.

Here’s the main process loop. It is executed twice per second as long as the timer ticks, i.e. as long as we’re not in Sleeping mode:

/// <summary>
/// Main process loop.
/// </summary>
private void Timer_Tick(object sender, object e)
{
    try
    {
        switch (state)
        {
            case BurglarAlertState.Sleeping:
                break;
            case BurglarAlertState.Active:
                if (irSensor.Sensor.CurrentState == 
	GrovePi.Sensors.SensorStatus.On)
                {
                    State = BurglarAlertState.MotionDetected;
                }
                break;
            case BurglarAlertState.MotionDetected:
                // Toggle LED
                ToggleLed();

                Log.Info("Motion detected " + 
	(DateTime.Now - motionDetection).Seconds.ToString());
                var delay = (DateTime.Now - motionDetection).Seconds;
                Info = string.Format("Motion detected ({0})", 10 - delay);

                if (delay > 10)
                {
                    if (irSensor.Sensor.CurrentState == 
	GrovePi.Sensors.SensorStatus.On)
                    {
                        State = BurglarAlertState.Alerting;
                    }
                    else
                    {
                        State = BurglarAlertState.Active;
                    }
                }
                break;
            case BurglarAlertState.Alerting:
                // Toggle LED
                ToggleLed();
                break;
            default:
                break;
        }
    }
    catch (Exception ex)
    {
        Log.Error(ex.Message);
    }
}

For the sake of completion, here’ s what happens when the state is changed:

public BurglarAlertState State
{
    get { return state; }
    set
    {
        blinky.Sensor.ChangeState(
	GrovePi.Sensors.SensorStatus.Off);
        buzzer.Sensor.ChangeState(
	GrovePi.Sensors.SensorStatus.Off);

        SetProperty(ref state, value);

        Info = State.ToString();

        switch (state)
        {
            case BurglarAlertState.Sleeping:
                timer.Stop();
                break;
            case BurglarAlertState.Active:
                timer.Start();
                break;
            case BurglarAlertState.MotionDetected:
                motionDetection = DateTime.Now;
                break;
            case BurglarAlertState.Alerting:
                try
                {
                    buzzer.Sensor.ChangeState(
	GrovePi.Sensors.SensorStatus.On);
                }
                catch (Exception ex)
                {
                    Log.Error(ex.Message);
                }
                break;
            default:
                break;
        }
    }
}

Here’s the Burglar Alert app and its sensors in action:

burglar

There are more projects in the making …

Source Code

The project lives here on GitHub.

Enjoy!

Advertisements

A Floating Panel Control for UWP

Windows Apps need to run in an increasing number of window sizes and resolutions and fortunately the Windows 10 ecosystem helps us with things like the RelativePanel and Visual State Triggers. But not all positioning issues can or should be solved by responsive layout techniques. Sometimes it’s just better to let the user decide where a control should be positioned. In a UI that shows a diagram –for example- it’s hard to predict where the bars or lines or shapes will appear. For that same diagram it’s also hard to predict the size of the legend: it depends on the number of series and the length of their names. In this case it would be appropriate to let the user drag the legend panel to a ‘free’ area in the diagram.

In this article we’ll build a XAML Control for the Universal Platform that can be dragged around the screen. Its position can optionally be restrained to a parent control’s rectangle or to the window itself. The control is decorated with an icon to indicate its ‘draggability’ behavior to the user.

Here’s how to use it:

<controls:FloatingContent Boundary="Parent">
    <!-- Any Content Here ... -->
</controls:FloatingContent>

As usual, we built a control together with a sample app. This app contains some instances of the so-called FloatingContent that are differently configured:

  • Joy is unbound, she can be dragged off the screen, 
  • Disgust is bound to the Window,
  • Sadness is bound to [the root control of] the Page (as you will see, this makes a subtle difference), 
  • Anger is bound to the red Border and doesn’t like it, and
  • Fear is also bound to the red Border, but he has a Margin.

Here’s how that app looks like:

FloatingContentControl

Style

The control is yet another templated control. Here’s the ControlTemplate:

<ControlTemplate TargetType="local:FloatingContent">
    <!-- This Canvas never covers other controls -->
    <Canvas Background="Transparent"
            Height="0"
            Width="0"
            VerticalAlignment="Top"
            HorizontalAlignment="Left">
        <!-- This Border handles the dragging -->
        <Border x:Name="PART_Border"
                ManipulationMode="TranslateX, TranslateY, TranslateInertia">
            <Grid>
                <!-- Content -->
                <ContentPresenter />
                <!-- Overlay -->
                <!-- Anything with an Opacity will do here... -->
                <Path x:Name="PART_Overlay"
                        Data="...(long Path Data omitted)..."
                        Stretch="Uniform"
                        Opacity="0"
                        Fill="White"
                        Width="24"
                        Height="24"
                        Margin="8"
                        VerticalAlignment="Top"
                        HorizontalAlignment="Left" />
            </Grid>
        </Border>
    </Canvas>
</ControlTemplate>

The Border control inside the template handles the dragging: through its ManipulationMode it is set to react to  combined horizontal and vertical manipulation with inertia. That border is wrapped in a zero-height, zero-width Canvas. That’s because the Border’s position is changed by updating its Canvas.Top and Canvas.Left attached properties. Inside the Border there’s the ContentPresenter that … presents the content. On top of the content there’s an overlay that displays a ‘draggability’ icon.

Class Definition

The class is decorated with TemplatePart attributes for the Border and the Overlay, since we use these in the code. [Note to template designers: the code also heavily relies on the outer Canvas in the template, so don’t drop that.]

In most cases we let a custom control inherit from Control, but this time ContentControl is a better parent:

/// <summary>
/// A Content Control that can be dragged around.
/// </summary>
[TemplatePart(Name = BorderPartName, Type = typeof(Border))]
[TemplatePart(Name = OverlayPartName, Type = typeof(UIElement))]
public class FloatingContent : ContentControl
{
    private const string BorderPartName = "PART_Border";
    private const string OverlayPartName = "PART_Overlay";

    private Border border;
    private UIElement overlay;

The FloatingContent control has just one dependency propertyBoundary-, which is a value from the FloatingBoundary enumeration. Here are the relevant code snippets:

public enum FloatingBoundary
{
    None,
    Parent,
    Window
}
public static readonly DependencyProperty BoundaryProperty =
    DependencyProperty.Register(
        "Boundary",
        typeof(FloatingBoundary),
        typeof(FloatingContent),
        new PropertyMetadata(FloatingBoundary.None));

public FloatingBoundary Boundary
{
    get { return (FloatingBoundary)GetValue(BoundaryProperty); }
    set { SetValue(BoundaryProperty, value); }
}

During the initialization of the control’s look and feel in the OnApplyTemplate method

  • we first lookup the Border in the template, and throw an Exception if it’s not found (after all: there’s no floating behavior without that border).
  • Then we register an event handler for ManipulationDelta which will manage the movement of the control when it is dragged around.
  • Last but not least, we make sure that any initial positioning of the control is maintained, and
  • in order to keep the boundary hit detection algorithm simple, we replace the control’s Margin by its Border’s Padding:
protected override void OnApplyTemplate()
{
    // Border
    this.border = this.GetTemplateChild(BorderPartName) as Border;
    if (this.border != null)
    {
        this.border.ManipulationDelta += Border_ManipulationDelta;

        // Move Canvas properties from control to border.
        Canvas.SetLeft(this.border, Canvas.GetLeft(this));
        Canvas.SetLeft(this, 0);
        Canvas.SetTop(this.border, Canvas.GetTop(this));
        Canvas.SetTop(this, 0);

        // Move Margin to border.
        this.border.Padding = this.Margin;
        this.Margin = new Thickness(0);
    }
    else
    {
        // Exception
        throw new Exception("Floating Control Style has no Border.");
    }

    this.Loaded += Floating_Loaded;
}

When the control is loaded, we register an event handler to the SizeChanged of its parent. When that parent is resized, we may need to update the FloatingControl’s position:

private void Floating_Loaded(object sender, RoutedEventArgs e)
{
    FrameworkElement el = GetClosestParentWithSize(this);
    if (el == null)
    {
        return;
    }

    el.SizeChanged += Floating_SizeChanged;
}

We have to pick the right parent for this: by crawling up the Visual Tree we look for the closest control with an actual size, since that is the one that will decently respond to SizeChanged

/// <summary>
/// Gets the closest parent with a real size.
/// </summary>
private FrameworkElement GetClosestParentWithSize(FrameworkElement element)
{
    while (element != null && 
	(element.ActualHeight == 0 || element.ActualWidth == 0))
    {
        // Crawl up the Visual Tree.
        element = element.Parent as FrameworkElement;
    }

    return element;
}

Runtime behavior

Dragging the control

The most important feature of the FloatingContent control, is following the pointer – finger, pen or mouse pointer, or other. This movement is triggered through the ManipulationDelta event handler. It calculates the theoretical –unbound- position of the control as a rectangle with top, left, width and height. It then calls the AdjustCanvasPosition() routine that will effectively update the control’s position:

private void Border_ManipulationDelta(object sender, 
	ManipulationDeltaRoutedEventArgs e)
{
    var left = Canvas.GetLeft(this.border) + e.Delta.Translation.X;
    var top = Canvas.GetTop(this.border) + e.Delta.Translation.Y;

    Rect rect = new Rect(
	left, 
	top, 
	this.border.ActualWidth, 
	this.border.ActualHeight);
    var moved = AdjustCanvasPosition(rect);

    // Not intuitive:
    //if (!moved)
    //{
    //    // We hit the boundary. Stop the inertia.
    //    e.Complete();
    //}
}

The move-the-control code returns a Boolean to let the caller know whether or not the manipulation did actually move the control. He may want to react on this. The commented code in the previous snippet implements some kind of auto-docking feature that stops all movement when a boundary is hit.

As already mentioned, the floating control is moved by updating its Canvas.Top and Canvas.Left attached properties and is constrained by its Boundary type:

  • When Boundary is None, no checks are done: the theoretical position becomes the actual position.
  • When Boundary is Parent, we’ll look up the closest parent with an actual size in the Visual Tree, and apply a collision detection algorithm.
  • When the Boundary is Window, we look up the relative position of the control in the app’s Window through TransformToVisual and Window.Current, and then adjust when a collision was detected.

Here’s the whole routine, except for the collision detection calculation which is fairly obvious:

/// <summary>
/// Adjusts the canvas position according to the Boundary property.
/// </summary>
/// <returns>True if there was a move, otherwise False.</returns>
private bool AdjustCanvasPosition(Rect rect)
{
    // Free floating.
    if (this.Boundary == FloatingBoundary.None)
    {
        Canvas.SetLeft(this.border, rect.Left);
        Canvas.SetTop(this.border, rect.Top);

        return true;
    }

    FrameworkElement el = GetClosestParentWithSize(this);

    // No parent
    if (el == null)
    {
        // We probably never get here.
        return false;
    }

    var position = new Point(rect.Left, rect.Top); ;

    if (this.Boundary == FloatingBoundary.Parent)
    {
        Rect parentRect = new Rect(0, 0, el.ActualWidth, el.ActualHeight);
        position = AdjustedPosition(rect, parentRect);
    }

    if (this.Boundary == FloatingBoundary.Window)
    {
        var ttv = el.TransformToVisual(Window.Current.Content);
        var topLeft = ttv.TransformPoint(new Point(0, 0));
        Rect parentRect = new Rect(topLeft.X, topLeft.Y, 
	Window.Current.Bounds.Width - topLeft.X, 
	Window.Current.Bounds.Height - topLeft.Y);
        position = AdjustedPosition(rect, parentRect);
    }

    // Set new position
    Canvas.SetLeft(this.border, position.X);
    Canvas.SetTop(this.border, position.Y);

    return position == new Point(rect.Left, rect.Top);
}

Note: when the Boundary is set to Window and you’re using a SplitView on the page, then the FloatingContent will remain on the window as expected, but it can be dragged under the Splitview’s Pane. That’s what we did with Disgust in the screenshots. If you don’t want that behavior, then use Parent for Boundary and place the control in the page’s root – that’s how we configured Sadness.

Showing the Draggability Indicator

When the user hovers over the control, when he taps on it, and when he’s dragging the control around, the FloatingContent displays a ‘dragging indicator’ in its upper left corner. It’s the white icon in Anger -not the red arrow- in the following screenshot:

FloatingContentControlOverlay

That so-called Overlay is defined in the control’s style, with a zero Opacity. We let the icon appear and disappear by animating this Opacity. That’s why we define it as UIElement instead of the Path in the style definition: the designer of a custom template can choose any element that comes with Opacity.

The overlay

All event handlers are registered in the OnApplyTemplate:

protected override void OnApplyTemplate()
{
    // Border
    this.border = this.GetTemplateChild(BorderPartName) as Border;
    if (this.border != null)
    {
        this.border.ManipulationStarted += Border_ManipulationStarted;
        this.border.ManipulationCompleted += Border_ManipulationCompleted;
        this.border.Tapped += Border_Tapped;
        this.border.PointerEntered += Border_PointerEntered;
    }
    else
    {
        // Exception
        throw new Exception("Floating Control Style has no Border.");
    }

    // Overlay
    this.overlay = GetTemplateChild(OverlayPartName) as UIElement;
}

The dragging icon appears and disappears smoothly. We defined a StoryBoard with a DoubleAnimation on Opacity. Here’s the code for one of the event handlers:

private void Border_ManipulationStarted(object sender, 
	ManipulationStartedRoutedEventArgs e)
{
    if (this.overlay != null)
    {
        var ani = new DoubleAnimation()
        {
            From = 0.0,
            To = 1.0,
            Duration = new Duration(TimeSpan.FromSeconds(1.5))
        };
        var storyBoard = new Storyboard();
        storyBoard.Children.Add(ani);
        Storyboard.SetTarget(ani, overlay);
        ani.SetValue(Storyboard.TargetPropertyProperty, "Opacity");
        storyBoard.Begin();
    }
}

The other event handlers are similar. The flash effect is the same as the fade-in, but with AutoReverse to True.

It’s Universal

Here’s how the control looks like on Windows 10 Mobile. In the right screenshot, Sadness is showing the dragging overlay. Also observe that when the Boundary is set to Screen –look at Disgust– the control can be dragged under the phone’s StatusBar. Again, if you don’t want this to happen, configure the control like Sadness and use the page’s root as boundary:

FloatingContentControlPhone FloatingContentControlPhoneOverlay

Here’s how the sample app looks like on the Raspberry Pi:

FloatingContentControlRaspberryPi

[Yep: in my house, the smallest computer gets the biggest screen.]

The code

The control and its sample app live here on GitHub. The FloatingContent control has its own project.

Enjoy!