In the first part of the article I’ve shown how UWP can be great for creating desktop applications running on Windows 10. This might not be an option for you as you still need to support Windows 7 – or you have existing WPF applications that cannot be migrated that easily to UWP. In the second part of this article series I’m adding information how WPF applications can be enhanced with features from Windows 10. This time I’m using the Desktop Bridge.
The desktop bridge is a technology to allow using Windows Runtime APIs from WPF apps. Just be aware – there’s a reason for the picture I’ve chosen for this article. It’s a bridge, but the bridge is a little bit shaky.
The first part is extremely easy to do. You can create an APPX package and run the WPF application from this package. The sample code includes a WPF project named DesktopBridgeSample. The app package project is named DesktopBridgeSample.Package. To create such a package project, you can use the Visual Studio project template Windows Application Packaging Project. To enhance WPF, you probably wouldn’t search for this template in the category Windows Universal. However, as you enhance the WPF application with Windows Universal features, it makes sense to have this project template in this category.
After creating this project type, in the Solution Explorer you can see Applications. Clicking on Applications, you can add a reference to the WPF application.
With the Windows Application Package Project, you can configure the application like you are used to do with Universal Windows apps. With the project properties, you need to configure the minimum and target version of Windows. The desktop bridge was introduced with Windows 10 build 1607, but you can use it with apps targeting the older Windows Anniversary Update, build 14393.
Opening the Package.appxmanifest editor, you can configure the application, visual assets, capabilities of the app, and more Windows 10 specific configurations. Using the application settings you can configure an URL from an back-end server that returns XML tile information to update the application tile on a specified recurrence between 30 minutes and one day. Visual assets allow to configure default images for the tiles in various resolutions. Capabilities allow to configure features that the app should be allowed to use – such as accessing location information, or access to the pictures library. The user still has to agree to these capabilities. Declarations allow you to specify the contracts the application implements. For example, you can share data with other Universal apps.
With this project in place, you can start the WPF application directly, or by starting the package project. Starting the application with the package project, the application needs to be deployed before it is started. In the Output window you can see the deployment in action – if the Configuration Manager is configured to deploy the application automatically.
Using Windows Application Packing Projects to package a WPF application, the WPF application becomes a packaged app.
Using Windows Runtime APIs
Using Windows Runtime APIs, references to the metadata files for the Windows Runtime need to be added to the WPF project. Currently, in the Reference Manager, the Browse… button needs to be used to reference these files. The table lists the files and their location where you can find the files.
Be aware adding references using Browse… adds the files using relative locations. As these files are typically outside of your project, the relative location no longer works when you move the project to a different directory. Probably you want to change the directories to absolute directories. Here, the files still need to exist in the referenced location on your development system.
Some of the Windows Runtime APIs require the application to run from a package. To see information about the package I’ve created the
PackageNameService class which uses the
Package API from the
Windows.ApplicationModel namespace. The method
GetPackageName returns the display name and full name of the package. In case the application is not running within a package, when accessing the
Current property of the
InvalidOperationException is thrown. Catching this exception,
"no package" is returned.
The APIs currently available for packaged apps are listed in UWP APIs available to a packaged desktop app (Desktop Bridge).
One API that can only be used from packaged apps is updating of the tile. Using the
BadgeUpdateManager, the sample code updates the badge number of the tile every time the
UpdateTile method is invoked:
Starting UWP Apps from WPF
Packaged apps can’t use all APIs of the Windows Runtime. Indeed, many APIs are still missing. For example, you can’t use Windows APIs in need of a window. However, you can create a UWP application where you can use all the Windows Runtime features, and communicate with this application from WPF.
To allow starting the UWP application from WPF, you can add a declaration to the UWP application to start it via a protocol. With the sample application, the UWP app is started via the sampleapp protocol.
Within the overridden
OnActivated method in the
App class, the UWP application checks if it was activated via protocol, and passes such information to the main page:
From the WPF application, the
Launcher class from the
Windows.System namespace is used to launch the UWP application via the protocol. This API is available for packaged apps.
Communication via App Services
Using the UWP app, you can use all the features from the Windows Runtime, and all the new controls with e.g. ink and map functionality. You just might need to communicate information from the UWP app with the WPF application. To communicate between UWP and WPF, App Services can be used. This API is available for packaged apps as well.
App Services previously have been only available creating Windows Runtime Components. Now they can be implemented in the UWP app which makes the communication between UWP and WPF easier.
Creating an App Service, Windows needs to know about it to allow starting the component. This is done selecting Declarations in the Package Manifest Editor, adding an App Service. The name needs to be unique on the system. For unique names it’s useful to include your own domain, such as com.cninnovation.desktopbridge. Using the in-app mode it’s not necessary to define an entry point – contrary to when the app service is implemented with a Windows Runtime Component.
When the app service is instantiated, within the
OnBackgroundActivated method in the
App class gets invoked. When a message is received, the
RequestReceived event is fired. Data can be transferred passing information in a
ValueSet. The handler method
OnAppRequestReceived deals with messages from the WPF application and messages from the UWP application. If a message from the WPF application contains the
command key with the value
StartEvents, the app service connection is remembered to forward events coming from the UWP application across this connection. If the sender is different from the WPF application (the UWP application), the
ValueSet received is sent to WPF using the method
SendMessageAsync on the app service connection to the WPF application.
The UWP application initiates a connection to the app service with the
OpenAsync method of the
AppServiceConnection class and sends messages passing a
ValueSet to the
Similar to dealing with the app service in the UWP application, it’s done in the WPF application. The connection to the app service is opened with the
OpenAsync method of the
AppServiceConnection class. After the first message is sent to start receiving events, the main functionality is in the event handler for the event
RequestReceived. Here, an event is fired in the service class. The view-model subscribes to the event to add the information to an
ObservableCollection and in turn display the message in the user interface.
Adding references to the metadata files of the Windows Runtime could be made easier. Other than searching the files in the directory structure, you also need to pay attention on absolute or relative links in the project file. You might need to change this manually. Visual Studio by default add a relative link – which no longer works with links outside of the project structure when you move the project to a different directory.
Using communication across app services is probably not what you wish for. However, it’s not a hard task to enhance communication with ValueSet by adding a custom abstraction layer.
It’s still the best way to create new desktop applications using the Universal Windows Platform. However, the desktop bridge offers an easy way to enhance existing WPF applications for Windows 10 users. Some of the Windows Runtime APIs can directly be used from WPF as soon as the WPF application is offered as a packaged app. All features from UWP apps can be used by launching a UWP application from WPF, and communicating with this application using app services.
What’s a little bit messy is referencing the metadata files needed to invoke the Windows Runtime APIs form WPF, and also the communication via app services. Probably you would also prefer to use UWP controls directly within WPF user interfaces instead of the need to create a second window. Having extra windows can be too difficult for some users. The next article in this series describes how UWP controls can be directly used from within WPF applications – using XAML Islands.
In case you would like to enhance your WPF applications now – go ahead and use Windows Runtime APIs with the help of the desktop bridge.
If this information motivated you enhancing your WPF applications with UWP features, consider buying me a coffee which helps me staying up longer and writing more articles.
Enjoy learning and programming!