Il .NET Framework 2.0 offre due classi che consentono di sapere se una connessione di rete è disponibile e di ricevere notifiche quando lo stato della connessione cambia: si tratta rispettivamente di NetworkInterface e NetworkChange, entrambe contenute nel namespace System.Net.NetworkInformation. In particolare, NetworkChange è una classe statica che espone un metoodo di nome NetworkAvailabilityChanged, che viene generato quando lo stato della connessione cambia da non disponibile a disponibile, e viceversa.
Il problema di questa classe (se così si può chiamare) è che l'evento NetworkAvailabilityChanged viene generato in un thread secondario, quindi se si cerca di aggiornare l'interfaccia utente nell'handler di tale evento si ottiene un'eccezione causata dal tentativo di operazione cross-thread. Come è risaputo, in una situazione del genere è necessario utilizzare il metodo Invoke, così da garantire un accesso thread-safe ai controlli.
Come ho già scritto in questo post, è possibile evitare tale approccio utilizzando gli oggetti AsyncOperation e SendOrPostCallback. Non ci vuole molto per adattare il codice che avevo presentato in quell'occasione al nuovo contesto:
1 using System;
2 using System.ComponentModel;
3 using System.Threading;
4
5 namespace System.Net.NetworkInformation
6 {
7 public static class NetworkChange2
8 {
9 private static AsyncOperation operation;
10 private static SendOrPostCallback callback;
11
12 public static event NetworkAvailabilityChangedEventHandler
13 NetworkAvailabilityChanged;
14
15 static NetworkChange2()
16 {
17 callback = new SendOrPostCallback(Handler);
18 operation = AsyncOperationManager.CreateOperation(null);
19 NetworkChange.NetworkAvailabilityChanged +=
20 new NetworkAvailabilityChangedEventHandler
21 (NetworkChange_NetworkAvailabilityChanged);
22 }
23
24 public static bool IsNetworkAvailable()
25 {
26 return NetworkInterface.GetIsNetworkAvailable();
27 }
28
29 private static void NetworkChange_NetworkAvailabilityChanged
30 (object sender, NetworkAvailabilityEventArgs e)
31 {
32 operation.Post(callback, e);
33 }
34
35 private static void Handler(object stateInfo)
36 {
37 if (NetworkAvailabilityChanged != null)
38 NetworkAvailabilityChanged(null,
39 (NetworkAvailabilityEventArgs)stateInfo);
40 }
41 }
42 }
La classe NetworkChange2 non è altro che un wrapper per l'oggetto NetworkChange: quando quest'ultimo genera l'evento NetworkAvailabilityChanged, il suo gestore (righe 26-29) fa in modo di rilanciarlo all'interno del thread principale, attraverso il metodo Handler (righe 31-35).
L'utilizzo di questa nuova classe è immediato; è sufficiente cambiare le dichiarazioni come la seguente:
NetworkChange.NetworkAvailabilityChanged +=
new NetworkAvailabilityChangedEventHandler
(NetworkChange_NetworkAvailabilityChanged);
Utilizzando invece NetworkChange2:
NetworkChange2.NetworkAvailabilityChanged +=
new NetworkAvailabilityChangedEventHandler
(NetworkChange_NetworkAvailabilityChanged);
Fatto questo, all'interno del metodo NetworkChange_NetworkAvailabilityChanged sarà possibile accedere direttamente agli oggetti dell'interfaccia senza incorrere nell'errore InvalidOperationException.
Technorati tags:
.NET,
Programming,
CS