How to get notifications if devices are added, removed, or changed (XAML)

This tutorial shows you how to enumerate devices dynamically. Then, your app can receive notification if devices are added or removed, or if device properties change.

You use the DeviceWatcher class to start a device enumeration. For each device that's found, DeviceWatcher raises an Added event until all devices are found and the enumeration is complete. After the initial enumeration is complete, DeviceWatcher raises an EnumerationCompleted event and continues to raise events if a device is added, updated, or removed.

What you need to know

Technologies

  • Windows Runtime

Prerequisites

We assume that you are familiar with Visual C# and XAML.

Instructions

Step 1:

Open an instance of Microsoft Visual Studio.

Step 2: Create a new project

In the New Project dialog box, from the Visual C#/Windows Store style project types, pick a Blank Application.

Step 3: Insert the app XAML

Open your BlankPage.xaml and copy this code into the file, replacing the file's contents.

This XAML provides a user interface that lets users dynamically enumerate a list of all devices on their systems.

<Page
    x:Class="Application1.BlankPage"
    xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:Application1"
    xmlns:d="https://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="https://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">

    <Grid x:Name="ContentRoot" Background="Black" Margin="100,20,100,20">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>

        <!-- Header -->
        <StackPanel x:Name="Header" Grid.Row="0">
            <StackPanel Orientation="Horizontal"/>
        </StackPanel>

        <!-- Content -->
        <ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto" Grid.Row="1" ZoomMode="Disabled">
            <StackPanel x:Name="ContentPanel">
                <TextBlock Text="Device Enumeration Sample" Margin="0,25,0,20" Height="25" />

                <StackPanel x:Name="InputPanel" Orientation="Horizontal" HorizontalAlignment="Left" Height="266">
                    <StackPanel/>
                    <StackPanel x:Name="Description" MaxWidth="900">

                        <!-- Enumerate Device Interfaces -->
                        <StackPanel x:Name="EnumerateDevicesInput" Height="270" Width="857">

                            <TextBlock Text="Input" Margin="0,25,0,20" />

                            <TextBlock TextWrapping="Wrap" Text="This example app incrementally enumerates devices, adding them to a list each time a device is found, and also watching for updates. After enumeration is complete, the app prints the list of devices. The app reprints the list if devices are updated, removed, or added." HorizontalAlignment="Left"/>
                            <StackPanel Orientation="Horizontal" Margin="0,10,0,0"/>
                            <StackPanel Orientation="Horizontal" Margin="0,10,0,0"/>
                            <Button Name="WatchAllDevices" Content="Watch (All devices)" Margin="0,10,10,0" Click="WatchDevices" />
                            <Button Name="StopAllWatcher" Content="Stop" Margin="0,10,10,0" Click="StopWatcher" />
                        </StackPanel>

                    </StackPanel>
                </StackPanel>
                <TextBlock Text="Output" Margin="0,25,0,20" />

                <!-- Output section -->
                <StackPanel x:Name="Output"  HorizontalAlignment="Left">
                    <TextBlock Name="OutputText" />

                    <!-- Device Interfaces-->
                    <ListBox Name="DeviceInterfacesOutputList" IsEnabled="False" BorderThickness="0" />

                </StackPanel>
            </StackPanel>
        </ScrollViewer>

    </Grid>
</Page>

Step 4: Insert the app C#

Open your project's BlankPage.xaml.cs file and replace the existing code with this code.

The app lists the devices. If devices are added, deleted, or updated the list changes.

using System;
using System.Threading.Tasks;
using System.Collections.Generic;
using System.IO;
using System.Diagnostics;
using System.Linq;
using System.Text;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
using Windows.UI.Xaml.Media.Imaging;

using Windows.Devices.Enumeration;
using Windows.Devices.Enumeration.Pnp;


// The Blank Page item template is documented at https://go.microsoft.com/fwlink/?LinkId=234238

namespace Application1
{
    /// <summary>
    /// An empty page that can be used on its own or navigated to within a Frame.
    /// </summary>
    /// 
    public sealed partial class BlankPage : Page
    {
        public BlankPage()
        {

            this.InitializeComponent();
        }
        Windows.UI.Core.CoreDispatcher dispatcher;
        public static DeviceWatcher watcher = null;
        public static int count = 0;
        public static DeviceInformation[] interfaces = new DeviceInformation[1000];
        public static bool isEnumerationComplete = false;
        public static string StopStatus = null;

        async void WatchDevices(object sender, RoutedEventArgs eventArgs)
        {
            try
            {
                dispatcher = Window.Current.CoreWindow.Dispatcher;
                watcher = DeviceInformation.CreateWatcher();
                // Add event handlers
                watcher.Added += watcher_Added;
                watcher.Removed += watcher_Removed;
                watcher.Updated += watcher_Updated;
                watcher.EnumerationCompleted += watcher_EnumerationCompleted;
                watcher.Stopped += watcher_Stopped;
                watcher.Start();
                OutputText.Text = "Enumeration started.";

            }
            catch (ArgumentException)
            {
                //The ArgumentException gets thrown by FindAllAsync when the GUID isn't formatted properly
                //The only reason we're catching it here is because the user is allowed to enter GUIDs without validation
                //In normal usage of the API, this exception handling probably wouldn't be necessary when using known-good GUIDs 
                OutputText.Text = "Caught ArgumentException. Failed to create watcher.";
            }
        }

        async void StopWatcher(object sender, RoutedEventArgs eventArgs)
        {
            try
            {
                if (watcher.Status == Windows.Devices.Enumeration.DeviceWatcherStatus.Stopped)
                {
                    StopStatus = "The enumeration is already stopped.";
                }
                else
                {
                    watcher.Stop();
                }
            }
            catch (ArgumentException)
            {
                OutputText.Text = "Caught ArgumentException. Failed to stop watcher.";
            }
        }

        async void watcher_Added(DeviceWatcher sender, DeviceInformation deviceInterface)
        {
            interfaces[count] = deviceInterface;
            count += 1;
            if (isEnumerationComplete)
            {
                await dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
                {
                    DisplayDeviceInterfaceArray();
                });
            }
        }

        async void watcher_Updated(DeviceWatcher sender, DeviceInformationUpdate devUpdate)
        {
            int count2 = 0;
            foreach (DeviceInformation deviceInterface in interfaces)
            {
                if (count2 < count)
                {
                    if (interfaces[count2].Id == devUpdate.Id)
                    {
                        //Update the element.
                        interfaces[count2].Update(devUpdate);
                    }

                }
                count2 += 1;
            }
            await dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
            {
                OutputText.Text = "Enumeration updated. ";
                DisplayDeviceInterfaceArray();
            });
        }

        async void watcher_Removed(DeviceWatcher sender, DeviceInformationUpdate devUpdate)
        {
            int count2 = 0;
            //Convert interfaces array to a list (IList).
            List<DeviceInformation> interfaceList = new List<DeviceInformation>(interfaces);
            foreach (DeviceInformation deviceInterface in interfaces)
            {
                if (count2 < count)
                {
                    if (interfaces[count2].Id == devUpdate.Id)
                    {
                        //Remove the element.
                        interfaceList.RemoveAt(count2);
                    }

                }
                count2 += 1;
            }
            //Convert the list back to the interfaces array.
            interfaces = interfaceList.ToArray();
            count -= 1;
            await dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
            {
                OutputText.Text = "Enumeration device was removed. ";
                DisplayDeviceInterfaceArray();
            });
        }

        async void watcher_EnumerationCompleted(DeviceWatcher sender, object args)
        {
            isEnumerationComplete = true;
            await dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
                {
                    OutputText.Text = "Enumeration complete. ";
                    DisplayDeviceInterfaceArray();
                });
        }

        async void watcher_Stopped(DeviceWatcher sender, object args)
        {
            if (watcher.Status == Windows.Devices.Enumeration.DeviceWatcherStatus.Aborted)
            {
                StopStatus = "Enumeration stopped unexpectedly. Click Watch to restart enumeration.";
            }
            else if (watcher.Status == Windows.Devices.Enumeration.DeviceWatcherStatus.Stopped)
            {
                StopStatus = "You requested to stop the enumeration. Click Watch to restart enumeration.";
            }
        }

        async void DisplayDeviceInterfaceArray()
        {
            DeviceInterfacesOutputList.Items.Clear();
            int count2 = 0;
            foreach (DeviceInformation deviceInterface in interfaces)
            {
                if (count2 < count)
                {
                    DisplayDeviceInterface(deviceInterface);
                }
                count2 += 1;
            }
        }

        async void DisplayDeviceInterface(DeviceInformation deviceInterface)
        {
            var id = "Id:" + deviceInterface.Id;
            var name = deviceInterface.Name;
            var isEnabled = "IsEnabled:" + deviceInterface.IsEnabled;


            var item = id + " is \n" + name + " and \n" + isEnabled;

            DeviceInterfacesOutputList.Items.Add(item);
        }
    }
}

Remarks

This example incrementally enumerates devices. It adds them to a list each time a device is found, and also watches for updates. After enumeration is complete, the app prints a list of devices. The app also reprints the list of devices if a user added, updated, or removed any devices after the initial enumeration completes.