How To Use Surface Dial With WPF Applications

Editor’s note: The following post was written by Windows Development MVP Ricardo Pons as part of our Technical Tuesday series with support from his technical editor, Senior Technical Evangelist Amin Espinoza.

A few weeks ago, Microsoft launched the new Surface Dial - a device that promises to improve the user experience (UX) with Surface Studio, touch screen laptops, and PC’s with Windows 10 installed.

In this article, I will try to explain, with a simple example, how to use the new Surface Dial with WPF Applications.

Developing applications for WPF

Microsoft has published some code examples for Surface Dial that demonstrate what developers can do with this great device:

Using UWP (Universal Windows Platform) we have this code example: https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/RadialController

Using Classic Desktop Apps, we have this code example: https://github.com/Microsoft/Windows-classic-samples/tree/master/Samples/RadialController

Personally, I like to develop applications for UWP apps, but I couldn’t find any decent documentation explaining how to use this device with WPF - because, in my case, I would like to integrate it to improve the UX.

So how do we do this?

First of all, we need to install the Nuget package UwpDesktop. We need to understand that there is no native support for this device. As UWP applications we will need to use Interoperability (If you want to know more about this topic you can read this great documentation). We need to create the interfaces to access to the device:

  [System.Runtime.InteropServices.Guid("787cdaac-3186-476d-87e4-b9374a7b9970")]

    [System.Runtime.InteropServices.InterfaceType(System.Runtime.InteropServices.ComInterfaceType.InterfaceIsIInspectable)]

    interface IRadialControllerConfigurationInterop

    {

        RadialControllerConfiguration GetForWindow(

        IntPtr hwnd,

        [System.Runtime.InteropServices.In]ref Guid riid);

    }


[System.Runtime.InteropServices.Guid("1B0535C9-57AD-45C1-9D79-AD5C34360513")]

    [System.Runtime.InteropServices.InterfaceType(System.Runtime.InteropServices.ComInterfaceType.InterfaceIsIInspectable)]

    interface IRadialControllerInterop

    {

        RadialController CreateForWindow(

        IntPtr hwnd,

        [System.Runtime.InteropServices.In]ref Guid riid);

    }

After that we need to get the Hwnd of the current Window in our WPF Application:

 Window window = Window.GetWindow(this);
var wih = new WindowInteropHelper(window);
IntPtr hWnd = wih.Handle;

Because RadialController lives in Windows.UI.Input we needed to add the nugget Package UwpDesktop and we will use interop classes.

 var interop = 
(IRadialControllerInterop)System.Runtime.InteropServices.WindowsRuntime.WindowsRuntimeMarshal.GetActivationFactory(typeof(RadialController));

We need to get the GUID of our Device:

  Guid guid = typeof(RadialController).GetInterface("IRadialController").GUID;

Finally, we can call the method CreateForWindow passing the hWnd parameter of our current Window:

  controller = interop.CreateForWindow(hWnd, ref guid);
            controller.ControlAcquired += Controller_ControlAcquired;
            controller.ControlLost += Controller_ControlLost;
            controller.RotationChanged += Controller_RotationChanged;
            controller.ButtonClicked += Controller_ButtonClicked;

We can personalize the Radial Menu of the Surface Dial (adding our custom menu items), by doing something like this:

     var button = RadialControllerMenuItem.CreateFromKnownIcon("Item 1", RadialControllerMenuKnownIcon.Ruler);
           
            var button2 = RadialControllerMenuItem.CreateFromKnownIcon("Item 2", RadialControllerMenuKnownIcon.PenType);
            button.Invoked += Button_Invoked;

controller.Menu.Items.Add(button);
controller.Menu.Items.Add(button2);

Here is the final code to connect the Surface Dial to our WPF Application:

    private void StarController()
        {
            var interop = (IRadialControllerInterop)System.Runtime.InteropServices.WindowsRuntime.WindowsRuntimeMarshal
                .GetActivationFactory(typeof(RadialController));

            Guid guid = typeof(RadialController).GetInterface("IRadialController").GUID;

            Window window = Window.GetWindow(this);
            var wih = new WindowInteropHelper(window);
            IntPtr hWnd = wih.Handle;

            controller = interop.CreateForWindow(hWnd, ref guid);
            controller.ControlAcquired += Controller_ControlAcquired;
            controller.ControlLost += Controller_ControlLost;
            controller.RotationChanged += Controller_RotationChanged;
            controller.ButtonClicked += Controller_ButtonClicked;
            
            controller.RotationResolutionInDegrees = 1;
            var button = RadialControllerMenuItem.CreateFromKnownIcon("Item 1", RadialControllerMenuKnownIcon.Ruler);
           
            var button2 = RadialControllerMenuItem.CreateFromKnownIcon("Item 2", RadialControllerMenuKnownIcon.PenType);
            button.Invoked += Button_Invoked;
            button2.Invoked += Button_Invoked;
            controller.Menu.Items.Add(button);
            controller.Menu.Items.Add(button2);
            mainClicks = 0;
            
        }

I uploaded an example to GitHub. Please feel free to download and play with the code. screen-shot-2017-01-30-at-12-18-51-pm

Conclusion

Using Surface Dial will improve the user experience of our apps - and, what’s more,  we can create awesome applications for UWP Apps and Classic Desktop apps like WPF applications.

Even though we don’t have native support for Surface Dial, thanks to Interpo classes and UwpDesktop Nuget Package, we can use a lot of APIs from UWP applications in our Desktop apps to potentially improve their quality.


5001532Ricardo Pons is a lead architect specializing in Microsoft technologies, with a strong focus on Windows, .NET, Microsoft Azure & XAML Applications.  He is a highly-regarded Windows Platform developer in Mexico and Latin America. He likes to create high-quality consumer and enterprise applications, and has built many official applications for global companies for the Windows Phone and Windows Store. A blogger, consultant, speaker and entrepreneur, he was awarded as a Nokia Successful Developer in 2013 and received an Independent Developer Microsoft DX Award in 2014. Follow him on Twitter @RicardoPonsDev.