XAML Spy API

XAML Spy 3 includes an extensible API for automating and querying apps. The API consists of a .NET 4.5 assembly, providing access to live objects of a running app that is connected to XAML Spy.

The following tutorial introduces the XAML Spy API and provides step-by-step instructions on how to create a XAML Spy client console application, and query a connected app. Make sure you have downloaded and installed XAML Spy 3.

Setup

This section explains how to create a XAML Spy client from scratch.

  1. Open Visual Studio and create a new console application.
  2. Add a reference to the XamlSpy.Core assembly, located in the XAML Spy installation folder (default: C:\Program Files (x86)\First Floor Software\XAML Spy). XamlSpy.Core contains the XAML Spy API
  3. Open Program.cs and add the following code;
using FirstFloor.XamlSpy;
using FirstFloor.XamlSpy.Networking;
using FirstFloor.XamlSpy.Services;
using FirstFloor.XamlSpy.Services.Client;

class Program
{
    static void Main(string[] args)
    {
        Initialize();
        Console.ReadKey();
    }

    static async void Initialize()
    {
        var client = ServiceProvider.GetService<ClientService>();
        client.Closed += OnClosed;
        Console.Write("Connecting to XAML Spy...");
        await client.ConnectAsync();
        Console.WriteLine("OK");
        Console.WriteLine("Found " + client.Apps.Count + " apps");

        client.Close();
    }

    static void OnClosed(object sender, ClosedEventArgs e)
    {
        Console.WriteLine("Closed: " + e.Reason);
    }
}

The static ServiceProvider provides access to XAML Spy services. It is used to retrieve the ClientService, which manages the connection with the XAML Spy service, and provides access to any connected app. The connection with the XAML Spy service is initiated by invoking the asynchronous ConnectAsync method. The connection is closed by invoking Close. The ClientService.Apps property is a collection of connected apps. Executing the code results in the following output;

Console output

No apps have connected yet, time to track connected apps.

Tracking app lifetime

In order to track apps, the ClientService includes AppConnected and AppDisconnected events. Once a connection with an app has been established, the app (an instance of RemoteApp) is added to the ClientService.Apps collection. Modify the Initialize method and add event handlers for listening to app connectivity.

static async void Initialize()
{
    var client = ServiceProvider.GetService<ClientService>();
    client.AppConnected += OnAppConnected;
    client.AppDisconnected += OnAppDisconnected;
    client.Closed += OnClosed;
    Console.Write("Connecting to XAML Spy...");
    await client.ConnectAsync();
    Console.WriteLine("OK");
}

static void OnAppConnected(object sender, AppEventArgs e)
{
    Console.WriteLine("App connected: " + e.App);
}

static void OnAppDisconnected(object sender, AppDisconnectedEventArgs e)
{
    Console.WriteLine("App disconnected: " + e.App + ". Reason: " + e.Reason);
}

static void OnClosed(object sender, ClosedEventArgs e)
{
    Console.WriteLine("Closed: " + e.Reason);
}

Note that the client is no longer closed, the connection with the XAML Spy service is open until the console application is exited by pressing a key.

In order to demonstrate the app lifetime tracking, we need an app to connect to XAML Spy. Create a new, or open an existing app in a new instance of Visual Studio. Make sure XAML Spy is enabled for this app and launch it.

Compile and run the console app, and you should see a result similar to the following screenshot. In this case, a Windows 10 UWP app connects to, and disconnects from XAML Spy.

Console output

Querying remote objects

With the basic infrastructure in place, we can now do some very interesting things with a connected app. An instance of RemoteApp contains a set of methods to access the various hierachical structures exposed by XAML Spy. For example, GetVisualTree provides access to the visual tree. Each exposed tree structure is an implementation of IRemoteTree. This interface defines a set of methods for searching, and looking up remote objects. Every object in the tree, has a rich API for querying and setting its properties.

The following code snippet dumps the entire visual tree the moment an app connects.

static async void OnAppConnected(object sender, AppEventArgs e)
{
    Console.WriteLine("Hello " + e.App.Name);

    var tree = e.App.GetVisualTree();
    var visuals = await tree.GetDescendantsAsync();
    foreach (var visual in visuals) {
        Console.WriteLine(new string(' ', visual.Depth) + visual.DisplayName);
    }
    Console.WriteLine("Found " + visuals.Count + " visuals");
}

Console output

Wrapping up

In this tutorial you have learned how to get started with the XAML Spy API. Use the API to get access to a wealth of information of any connected app. The API is still under development, and subject to change.