Nessun risultato. Prova con un altro termine.
Guide
Notizie
Software
Tutorial

Enumerare i device

Link copiato negli appunti

In questo articolo vedremo come recuperare l'elenco delle periferiche connesse al sistema da un'applicazione Windows Store in XAML/C#. A volte infatti può essere necessario verificare se un particolare device è connesso e abilitato, oppure se più periferiche dello stesso tipo sono contemporaneamente disponibili sul sistema (come webcam e microfoni), in modo da consentire all'utente di scegliere quello più adatto alla situazione.

Il namespace Windows.Devices.Enumeration, mette a disposizione due strade per recuperare informazioni relative ai device connessi al sistema.

La prima opzione si basa sulla classe DeviceInformation, il cui metodo FindAllAsync permette di recuperare l'elenco delle periferiche disponibili in quel momento sul sistema. Questa opzione è utile per applicazioni Windows Store che non necessitano di notifica quando una delle periferiche connesse al sistema viene modificata o rimossa dal sistema, ovvero quando un nuovo device viene aggiunto all'elenco.

La seconda opzione sfrutta la classe DeviceWatcher, la quale non solo permette di recuperare l'elenco dei dispositivi connessi, ma solleva altresì specifici eventi ogniqualvolta la collezione di periferiche viene modificata. Nelle prossime pagine vedremo come implementare entrambe queste strategie.

Queste due strategie possono essere utilizzate anche per ricercare eventuali periferiche Plug and Play (Pnp) presenti sul sistema. Come vedremo, il namespace Windows.Devices.Enumeration.PnP mette a disposizione due classi, PnpObject e PnpDeviceWatcher, le quali svolgono sostanzialmente le medesime funzioni delle prime due.

Usare la classe DeviceInformation

Il codice seguente utilizza il metodo statico FindAllAsync per recuperare l'elenco delle periferiche disponibili sul sistema. Più precisamente, il metodo in questione restituisce un oggetto di tipo DeviceInformationCollection, il quale rappresenta una collezione di istanze di tipo DeviceInformation, ciascuna delle quali permette di accedere alle proprietà di un singolo device.

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Windows.Devices.Enumeration;
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.Media.Imaging;
using Windows.UI.Xaml.Navigation;
// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=234238
namespace Demo.Html.it.EnumeratingDeviceSample.CS
{
	/// <summary>
	/// An empty page that can be used on its own or navigated to within a Frame.
	/// </summary>
	public sealed partial class MainPage : Page
	{
		public MainPage()
		{
			this.InitializeComponent();
		}
		private async void EnumerateDevices_Click(object sender, RoutedEventArgs e)
		{
			var list = new List<DeviceItem>();
			var devices = await Windows.Devices.Enumeration.DeviceInformation.FindAllAsync();
			if (devices != null && devices.Count > 0)
			{
				foreach (DeviceInformation device in devices)
				{
					var glyph = await device.GetGlyphThumbnailAsync();
					var thumb = await device.GetThumbnailAsync();
					list.Add(new DeviceItem(device, thumb, glyph));
				}
			}
			DeviceListView.ItemsSource = list;
		}
		public class DeviceItem
		{
			public String DeviceName { get; set; }
			public String DeviceId { get; set; }
			public BitmapImage DeviceThumb { get; set; }
			public BitmapImage DeviceGlyph { get; set; }
			public DeviceItem(DeviceInformation deviceInterface, DeviceThumbnail thumbnail, DeviceThumbnail glyph)
			{
				this.DeviceName = (String)deviceInterface.Properties["System.ItemNameDisplay"];
				this.DeviceId = String.Format("Device ID: {0}", deviceInterface.Id);
				this.DeviceThumb = new BitmapImage();
				this.DeviceThumb.SetSource(thumbnail);
				this.DeviceGlyph = new BitmapImage();
				this.DeviceGlyph.SetSource(glyph);
			}
		}
	}
}

Dopo aver recuperato le informazioni sulle singole periferiche disponibili, il codice crea un nuovo oggetto di tipo DeviceItem, una classe custom che utilizziamo per tenere traccia delle informazioni raccolte, come il nome e l'ID della periferica, il thumbnail che rappresenta il dispositivo, nonché il relativo glifo ("glyph"), ossia il simbolo grafico associato a quel particolare device. Il thumbnail e il glifo possono essere recuperati in modo asincrono tramite due metodi specifici: rispettivamente, GetThumbnailAsync e GetGlyphThumbnailAsync. La collezione di device è quindi messa in binding con il controllo ListView e mostrato a video.

Per testare questo codice puoi usare come riferimento la seguente definizione XAML per la pagina MainPage.xaml della tua applicazione.

<Page x:Class="Demo.Html.it.EnumeratingDeviceSample.CS.MainPage"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
	  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
	  xmlns:local="using:Demo.Html.it.EnumeratingDeviceSample.CS"
	  xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
	  xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
	  mc:Ignorable="d">
	<UserControl.Resources>
		<DataTemplate x:Key="InterfaceItemTemplate">
			<StackPanel Margin="0,0,0,20">
				<TextBlock FontWeight="Bold" Style="{StaticResource SubheaderTextStyle}" Text="{Binding Path=DeviceName}" />
				<TextBlock Style="{StaticResource BasicTextStyle}" Text="{Binding Path=DeviceId}" />
				<StackPanel Orientation="Horizontal">
					<TextBlock VerticalAlignment="Center" Style="{StaticResource BasicTextStyle}" Text="Thumbnail:" />
					<Image Width="128" Height="128" Source="{Binding Path=DeviceThumb}" Margin="15,0,0,0"/>
				</StackPanel>
				<StackPanel Orientation="Horizontal">
					<TextBlock VerticalAlignment="Center" Style="{StaticResource BasicTextStyle}" Text="Glyph Thumbnail:" />
					<StackPanel Background="Blue" Margin="15,0,0,0">
						<Image Width="54" Height="54" Source="{Binding Path=DeviceGlyph}" />
					</StackPanel>
				</StackPanel>
			</StackPanel>
		</DataTemplate>
	</UserControl.Resources>
	<ScrollViewer>
		<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
			<StackPanel>
				<Button Click="EnumerateDevices_Click" Width="300" Height="50" Content="Elenca le periferiche" />
				<ListView x:Name="DeviceListView" ItemTemplate="{StaticResource InterfaceItemTemplate}" />
			</StackPanel>
		</Grid>
	</ScrollViewer>
</Page>

Se adesso eseguiamo l'app, dovremmo ottenere un risultato simile a quello mostrato nella prossima immagine (ovviamente l'elenco dei dispositivi connessi sarà differente).

La classe DeviceInformation espone diversi overload del metodo FindAllAsync, in modo da specificare quale tipo di periferiche cercare. Un primo overload, ad esempio, accetta come parametro un oggetto di tipo DeviceClass che indica il tipo di device da ricercare. In particolare, l'enum DeviceClass può assumere uno dei seguenti valori:

Valore Descrizione
All enumera tutte le periferiche connesse al sistema
AudioCapture enumera unicamente i device per la cattura audio
AudioRender enumera solo i dispositive per il rendering audio
PortableStorageDevice enumera i dispositivi di storage portatitili
VideoCapture enumera i device per la cattura video

Il seguente snippet mostra una versione rivista del codice iniziale che enumera unicamente i dispositivi di storage portatili presenti sul sistema:

private async void EnumerateDevices_Click(object sender, RoutedEventArgs e)
{
	var list = new List<DeviceItem>();
	var devices = await Windows.Devices.Enumeration.DeviceInformation.FindAllAsync(DeviceClass.PortableStorageDevice);
	if (devices != null && devices.Count > 0)
	{
		foreach (DeviceInformation device in devices)
		{
			var glyph = await device.GetGlyphThumbnailAsync();
			var thumb = await device.GetThumbnailAsync();
			list.Add(new DeviceItem(device, thumb, glyph));
		}
	}
	DeviceListView.ItemsSource = list;
}

Se eseguiamo nuovamente l'applicazione, vedremo che l'elenco mostrerà unicamente i dispositivi di storage rimovibili (se presenti sul sistema).

Gli altri due overload del metodo FindAllAsync consentono di specificare più nel dettaglio il tipo di periferica ricercata. Entrambi questi due metodi accettano infatti come parametro una stringa di tipo Advanced Query Syntax (AQS): si tratta di un particolare tipo di sintassi utilizza internamente da Windows per definire in modo dettagliato i parametri delle query di ricerca (come vedremo fra breve, uno di questi overload accetta anche, come secondo parametro, un array di stringhe che permette di specificare ulteriori proprietà del device da cercare all'interno dell'elenco dei dispositivi presenti sul sistema).

Possiamo usare questa stringa per specificare la classe implementata dalla periferica che stiamo cercando. Infatti, il driver di ogni dispositivo – fisico, logico o virtuale che sia – deve necessariamente fornire un nome che identifichi in modo univoco il dispositivo stesso. A partire da Windows 2000, questi driver utilizzano una classe (denominata device interface class) che permette di esporre le proprie funzionalità verso altri componenti di sistema. Ciascuna device interface class è associata a uno specifico GUID.

Il seguente codice mostra una versione rivista del metodo EnumerateDevices_Click già illustrato in precedenza, in modo da sfruttare la Advanced Query Syntax per elencare le stampanti connesse al sistema:

private async void EnumerateDevices_Click(object sender, RoutedEventArgs e)
{
	var list = new List<DeviceItem>();
	var selector = "System.Devices.InterfaceClassGuid:=\"{0ECEF634-6EF0-472A-8085-5AD023ECBCCD}\"";
	var devices = await Windows.Devices.Enumeration.DeviceInformation.FindAllAsync(selector);
	if (devices != null && devices.Count > 0)
	{
		foreach (DeviceInformation device in devices)
		{
			var glyph = await device.GetGlyphThumbnailAsync();
			var thumb = await device.GetThumbnailAsync();
			list.Add(new DeviceItem(device, thumb, glyph));
		}
	}
	DeviceListView.ItemsSource = list;
}

Se proviamo adesso l'applicazione, il risultato dovrebbe essere simile a quello mostrato nella prossima figura.

Le API di WinRT mettono a disposizione una serie di metodi che permettono di recuperare l'ID (o selector) dei tipi di periferiche più comunemente utilizzate. Qui di seguito sono riportati alcuni esempi (inclusi i nomi delle classi e dei relativi namespace), con i link alla documentazione ufficiale MSDN:

Windows.Media.Devices.MediaDevice.GetAudioCaptureSelector
Windows.Media.Devices.MediaDevice.GetAudioRenderSelector
Windows.Media.Devices.MediaDevice.GetVideoCaptureSelector
Windows.Media.Devices.MediaDevice.GetDefaultAudioRenderId
Windows.Media.Devices.MediaDevice.GetDefaultAudioCaptureId
Windows.Devices.Portable.StorageDevice.GetDeviceSelector
Windows.Devices.Portable.ServiceDevice.GetDeviceSelector
Windows.Devices.Portable.ServiceDevice.GetDeviceSelectorFromServiceId
Windows.Devices.Sms.SmsDevice.GetDeviceSelector
Windows.Networking.Proximity.ProximityDevice.GetDeviceSelector

Ad esempio, il codice seguente utilizza il metodo GetDeviceSelector della classe ProximityDevice per recuperare il selector corrispondente ai sensori di prossimità eventualmente installati sulla macchina:

private async void EnumerateDevices_Click(object sender, RoutedEventArgs e)
{
	var list = new List<DeviceItem>();
	var selector = Windows.Networking.Proximity.ProximityDevice.GetDeviceSelector();
	var devices = await Windows.Devices.Enumeration.DeviceInformation.FindAllAsync(selector);
	if (devices != null && devices.Count > 0)
	{
		foreach (DeviceInformation device in devices)
		{
			var glyph = await device.GetGlyphThumbnailAsync();
			var thumb = await device.GetThumbnailAsync();
			list.Add(new DeviceItem(device, thumb, glyph));
		}
	}
	DeviceListView.ItemsSource = list;
}

Il secondo overload del metodo FindAllAsync accetta come secondo parametro, oltre alla stringa AQS, un array di stringhe che permettono di specificare quali informazioni recuperare per ciascun device. Per default, infatti, gli oggetti di tipo DeviceInformation recuperati tramite il metodo FindAllAsync (così come quelli recuperati tramite il metodo CreateWatcher discusso nel prossimo paragrafo) incapsulano solo alcune delle informazioni disponibili: l'ID e il nome del device (esposte rispettivamente, dalle proprietà Id e Name della classe DeviceInformation); se la periferica è abilitata (la proprietà IsEnabled è true); se un certo device rappresenta la periferica di default per determinate operazioni (corrispondente alla proprietà IsDefault), nonché il percorso per raggiungere il device (mediante la proprietà EnclosureLocation).

Il seguente snippet, ad esempio, cerca di recuperare una serie di informazioni aggiuntive, come il friendly name della periferica, il produttore, il nome e il numero del modello (tieni presente che queste informazioni potrebbero non essere disponibili per tutte le periferiche):

private async void EnumerateDevices_Click(object sender, RoutedEventArgs e)
{
	var list = new List<DeviceItem>();
	var selector = "System.Devices.InterfaceClassGuid:=\"{0ECEF634-6EF0-472A-8085-5AD023ECBCCD}\"";
	var properties = new String[] {
		"System.Devices.FriendlyName",
		"System.Devices.Manufacturer",
		"System.Devices.ModelName",
		"System.Devices.ModelNumber"
	};
	var devices = await Windows.Devices.Enumeration.DeviceInformation.FindAllAsync(selector, properties);
	if (devices != null && devices.Count > 0)
	{
		foreach (DeviceInformation device in devices)
		{
			var glyph = await device.GetGlyphThumbnailAsync();
			var thumb = await device.GetThumbnailAsync();
			list.Add(new DeviceItem(device, thumb, glyph));
		}
	}
	DeviceListView.ItemsSource = list;
}

Le informazioni aggiuntive vengono incapsulate all'interno della proprietà Properties della classe DeviceInformation. Per l'elenco completo delle proprietà che possono essere recuperate tramite questo overload del metodo FindAllAsync (ovvero del metodo CreateWatcher discusso nel prossimo paragrafo) si rinvia alla documentazione ufficiale su MSDN.

Reagire alle modifiche nell'elenco delle periferiche disponibili tramite la classe DeviceWatcher

La classe DeviceWatcher consente di recuperare l'elenco delle periferiche in modo dinamico: dopo l'enumerazione iniziale, infatti, ogni volta che un device viene aggiunto, rimosso o modificato, vengono sollevati specifici eventi per segnalare che qualcosa è cambiato. Gli eventi esposti dalla classe DeviceWatcher sono i seguenti:

Evento Trigger
Added quando un nuovo device viene aggiunto alla collezione
EnumerationCompleted quando l'enumerazione iniziale delle periferiche è stato completato
Removed quando un device è rimosso dalla collezione
Stopped quando l'enumerazione viene interrotta
Updated quando un device della collezione viene aggiornato

Per enumerare dinamicamente le periferiche disponibili, è necessario per prima cosa ottenere una reference a un oggetto di tipo DeviceWatcher tramite il metodo statico CreateWatcher della classe DeviceInformation.

La seconda cosa da fare è abbonarsi ai vari eventi (tutti o solo alcuni, a seconda delle necessità) per essere notificati su qualunque cambiamento nell'elenco dei dispositivi. A questo punto, per avviare la ricerca iniziale dei device presenti sul sistema è sufficiente invocare il metodo Start della classe DeviceWatcher.

Vale la pena ricordare che il metodo CreateWatcher presenta anche tre overload che permettono di specificare i criteri di ricerca dei device. Questi overload accettano gli stessi parametri già visti quando abbiamo discusso il metodo FindAllAsync. Per l'uso dell'Advanced Query Syntax e per il recupero delle informazioni addizionali si rinvia pertanto al precedente paragrafo.

Il seguente snippet mostra un esempio di utilizzo della classe DeviceWatcher che recupera l'elenco dei dispositivi di storage rimovibili attualmente connessi al sistema e notifica all'utente ogni successiva modifica all'enumerazione iniziale.

public sealed partial class MainPage : Page
{
	private DeviceWatcher _watcher;
	private List<DeviceInformation> _deviceInfoList = new List<DeviceInformation>();
	public MainPage()
	{
		this.InitializeComponent();
		this._watcher = DeviceInformation.CreateWatcher(DeviceClass.PortableStorageDevice);
		this._watcher.Added += Watcher_Added;
		this._watcher.Updated += Watcher_Updated;
		this._watcher.Removed += Watcher_Removed;
		this._watcher.EnumerationCompleted += Watcher_EnumerationCompleted;
	}
	private async void StartWatcher_Click(object sender, RoutedEventArgs e)
	{
		if (this._watcher.Status != DeviceWatcherStatus.Started && this._watcher.Status != DeviceWatcherStatus.Stopping)
		{
			try
			{
				await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
					{
						this._watcher.Start();
						WatcherStatusTextBlock.Text += "Device Watcher avviato.\n";
					});
			}
			catch (Exception ex)
			{
				// ...
			}
		}
	}
	private async void Watcher_EnumerationCompleted(DeviceWatcher sender, object args)
	{
		await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
			{
				WatcherStatusTextBlock.Text += "Enumerazione completata.\n";
				DeviceCounterTextBlock.Text = String.Format("Ci sono {0} device sul tuo sistema.", this._deviceInfoList.Count);
			});
	}
	private async void Watcher_Removed(DeviceWatcher sender, DeviceInformationUpdate args)
	{
		await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
			{
				this._deviceInfoList.RemoveAll((e) => e.Id == args.Id);	WatcherStatusTextBlock.Text += "Un device è stato rimosso dall'elenco.\n";
				DeviceCounterTextBlock.Text = String.Format("Ci sono {0} device sul tuo sistema.", this._deviceInfoList.Count);
			});
	}
	private async void Watcher_Updated(DeviceWatcher sender, DeviceInformationUpdate args)
	{
		await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
			{
				WatcherStatusTextBlock.Text += "Un device è stato aggiornato.\n";
			});
	}
	private async void Watcher_Added(DeviceWatcher sender, DeviceInformation args)
	{
		await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
			{
				this._deviceInfoList.Add(args);
				var name = (String)args.Properties["System.ItemNameDisplay"];
				WatcherStatusTextBlock.Text += String.Format("Il seguente device è stato aggiunto all'elenco: {0}\n", name);
				DeviceCounterTextBlock.Text = String.Format("Ci sono {0} device sul tuo sistema.", this._deviceInfoList.Count);
			});
	}
	private async void StopWatcher_Click(object sender, RoutedEventArgs e)
	{
		if (this._watcher.Status != DeviceWatcherStatus.Stopped && this._watcher.Status != DeviceWatcherStatus.Stopping)
		{
			try
			{
				await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
					{
						this._watcher.Stop();
						WatcherStatusTextBlock.Text += "Device Watcher fermato.\n";
					});
			}
			catch (Exception ex)
			{
				// ...
			}
		}
	}
}

Durante l'enumerazione inziale, la classe DeviceWatcher scatena l'evento Added ogni volta che un nuovo device viene trovato sul sistema, fino a quando l'elenco non è completo. A questo punto viene scatenato l'evento EnumerationCompleted. A partire da questo momento, la classe DeviceWatcher continuerà a scatenare gli eventi di Added, Removed e Updated ogni volta che un nuovo device è, rispettivamente, aggiunto, rimosso o modificato.

Una volta che l'app non ha più bisogno di ricevere notifiche di eventuali cambiamenti nell'elenco dei device, è sufficiente invocare il metodo Stop.

Per testare il codice proposto, possiamo usare la seguente definizione XAML come riferimento per la pagina MainPage.xaml dell'applicazione:

<Page x:Class="Demo.Html.it.EnumeratingDeviceSample.CS.MainPage"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
	  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
	  xmlns:local="using:Demo.Html.it.EnumeratingDeviceSample.CS"
	  xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
	  xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d">
	<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
		<StackPanel>
			<StackPanel Orientation="Horizontal" Margin="20">
				<Button Click="StartWatcher_Click" Content="Start Watcher" Width="Auto" Height="50" Margin="10" />
				<Button Click="StopWatcher_Click" Content="Stop Watcher" Width="Auto" Height="50" Margin="10"/>
			</StackPanel>
			<TextBlock x:Name="DeviceCounterTextBlock" Width="Auto" Height="50" FontSize="22" Margin="20" />
			<TextBlock x:Name="WatcherStatusTextBlock" Width="Auto" Height="Auto" FontSize="22" Margin="20" TextWrapping="Wrap" />
		</StackPanel>
	</Grid>
</Page>

La prossima immagine mostra come la nostra semplice app reagisce ai cambiamenti nella collezione di device di storage rimovibili presenti sul sistema.

Vale la pena di osservare come il codice sopra riportato utilizzi l'enum DeviceWatcherStatus per controllare lo stato del DeviceWatcher prima di avviare o interrompere le relative operazioni. L'enum DeviceWatcherStatus può assumere uno dei seguenti valori:

Valore Descrizione
Created È lo stato iniziale dell'oggetto DeviceWatcher non appena instanziato. Durante questo stato, il client può registrare gli handler dei vari eventi.
Started Dopo che il metodo Start è stato invocato, il DeviceWatcher inizia a enumerare le periferiche connesse.
EnumerationCompleted Il DeviceWatcher ha completato l'enumerazione iniziale. Nuovi device possono essere aggiunti, modificati o rimossi dall'elenco.
Stopping Il metodo Stop è stato invocato dal client e il DeviceWatcher è in procinto di fermarsi. Nuovi eventi possono essere scatenati durante questo stato.
Stopped Il DeviceWatcher ha completato le sue operazioni. Nessun nuovo evento verrà sollevato al cambiare dell'elenco.
Aborted Il DeviceWatcher è stato interrotto dal sistema. Anche in questo caso non verranno scatenati nuovi eventi.

Il metodo Start non può essere invocato quando il DeviceWatcher è in stato di Started o Stopping. Il metodo Stop, dall'altro lato, solleva l'evento Stopped e il DeviceWatcher passa nell'evento di Stopping. Lo stato di Stopped verrà raggiunto solo dopo che tutti gli eventi già sollevati durante il processo sono stati completati.

La seguente immagine, presa dalla documentazione ufficiale su MSDN, mostra le transizioni tra i differenti stati del DeviceWatcher:

Enumerare i device Plug and Play (PnP)

Il namespace Windows.Devices.Enumeration.PnP consente di enumerare non soltanto i device, ma anche le device interface, le device interface class, e i device container. Un device interface rappresenta un link simbolico verso un device Plug and Play (PnP) che l'applicazione può usare per accedere al device stesso. Una device interface class è invece un'interfaccia che espone le funzionalità interne di ogni tipologia di device. Un device container, infine, rappresenta il device fisico vero e proprio e permette di accedere a informazioni interne del device (anziché alle sole funzionalità esposte tramite interfaccia), come il produttore o il nome del modello.

In particolare, il namespace Windows.Devices.Enumeration.PnP mette a disposizione la classe PnpObject per esporre una serie di informazioni relative alle varie periferiche presenti sul sistema, in modo simile a quanto già visto quando abbiamo discusso la classe DeviceInformation. Ad esempio, anche la classe PnpObject espone due metodi, FindAllAsync e CreateWatcher, già visti nei paragrafi precedenti. In questo caso, tuttavia, i due metodi accettano (oltre alla stringa AQS e l'indicazione delle informazioni da recuperare) un oggetto di tipo PnpObjectType, un enum che indica quale tipo di "oggetto" stiamo cercando.

Questo enum può assumere uno dei seguenti valori:

Valore Descrizione
Unknown Indica un oggetto di tipo sconosciuto. Questo valore non è solitamente usato.
DeviceInterface Indica di cercare tra le device interface.
DeviceContainer Indica di cercare tra i device container.
DeviceInterfaceClass Indica di cercare tra i device interface class.

Il prossimo snippet mostra un esempio di utilizzo della classe PnpObject che sfrutta il metodo FindAllAsync per recuperare (sotto forma di collezione di oggetti di tipo PnpObject) tutti i device container presenti sul sistema, assieme ad una serie di informazioni aggiuntive, come il friendly name, il numero del modello, il produttore e l'indicazione se la periferica è connessa o meno.

private async void EnumerateDevices_Click(object sender, RoutedEventArgs e)
{
	var list = new List<DeviceItem>();
	var properties = new String[] { "System.Devices.FriendlyName",
									"System.Devices.ModelName",
									"System.Devices.Manufacturer",
									"System.Devices.Connected" };
	var devices = await PnpObject.FindAllAsync(PnpObjectType.DeviceContainer, properties);
	foreach (var device in devices)
	{
		list.Add(new DeviceItem(device));
	}
	// mostra i container a video
}
public class DeviceItem
{
	public String DeviceFriendlyName { get; set; }
	public String DeviceModelName { get; set; }
	public String DeviceManufacturer { get; set; }
	public String DeviceConnected { get; set; }
	public DeviceItem(PnpObject container)
	{
		this.DeviceFriendlyName = (String)container.Properties["System.Devices.FriendlyName"];
		this.DeviceModelName = (String)container.Properties["System.Devices.ModelName"];
		this.DeviceManufacturer = (String)container.Properties["System.Devices.Manufacturer"];
		this.DeviceConnected = (String)container.Properties["System.Devices.Connected"].ToString();
	}
}

Come abbiamo detto, la classe PnpObject mette a disposizione anche la possibilità di utilizzare un oggetto di tipo PnpDeviceWatcher (sostanzialmente identico a quello rappresentato dalla classe DeviceWatcher già vista in precedenza) per tenere sotto controllo ogni modifica all'enumerazione iniziale. Il prossimo snippet mostra il tipico pattern già incontrato con la classe DeviceWatcher.

private PnpObjectWatcher _watcher;
private void EnumerateDevices_Click(object sender, RoutedEventArgs e)
{
	var properties = new String[] {
		"System.Devices.FriendlyName",
		"System.Devices.ModelName",
		"System.Devices.Manufacturer",
		"System.Devices.Connected" };
	this._watcher = PnpObject.CreateWatcher(PnpObjectType.DeviceInterfaceClass, properties);
	this._watcher.Added += Watcher_Added;
	this._watcher.Updated += Watcher_Updated;
	this._watcher.Removed += Watcher_Removed;
	this._watcher.EnumerationCompleted += Watcher_EnumerationCompleted;
	this._watcher.Start();
}

Ti consigliamo anche