The Windows Phone OS automatically chooses a connection type based on the following ordered priorities:
Network connection to a PC via a tethered connection
Mobile broadband
The Windows Phone OS favors a network connection via a PC above all other connection types. The phone periodically checks whether a higher priority connection is available and switches connections accordingly.
The API for determining the connection status of the device is located in the Microsoft.Phone.Net.NetworkInformation and System.Net.NetworkInformation namespaces. Within this API is an event for notification when a connection change occurs.
The System.Net.NetworkInformation.NetworkInterface
class and the System.Net.NetworkInformation.NetworkChange
class represent the non-phone-specific portion of the API, whereas the Microsoft.Phone.Net.NetworkInformation.NetworkInterface
inherits from System.Net.NetworkInformation.NetworkInterface
and is specific to the phone (see Figure 27.1).
The NetworkInterface.GetIsNetworkAvailable
method allows you to determine whether any network connection is available; however, there is one caveat (see the following note).
Note
GetIsNetworkAvailable
is not always a true indicator of whether a useable network is available. A network connection is considered to be available if any network interface is marked “up” and is not a loopback or tunnel interface. There are cases where the phone may not be connected to a network, yet a network is still considered available, and GetIsNetworkAvailable
returns true.
An alternative and albeit more reliable method for determining network availability is the NetworkInterface.NetworkInterfaceType
property. While the NetworkInterfaceType
enum includes many values, the phone implementation supports only the following five values:
None—Indicates that no network connection is established.
MobileBroadbandCdma—Indicates a connection to a CDMA cellular network.
MobileBroadbandGsm—Indicates a connection to a GSM cellular network.
Ethernet—Indicates a network connection is established via a PC. Ordinarily, this is done with a USB cable.
Wireless80211—Indicates a Wi-Fi connection is established to a LAN.
To determine whether the phone is connected to a network, the NetworkInterfaceType
property can be compared to the NetworkInterfaceType.None
enum value, as shown:
bool connected = NetworkInterface.NetworkInterfaceType
!= NetworkInterfaceType.None;
The NetworkInterfaceType.None
value represents a state where the phone does not have Internet access. As Dolhai points out in an article available at http://www.codeproject.com/KB/windows-phone-7/ZuneDetectAndNetworking.aspx, under some circumstances, such as disconnecting the phone from an Ethernet connection, reading the NetworkInterfaceType
property can block the calling thread for many seconds. It is advisable, therefore, to read the property from a background thread. In a moment you see how to do that using a custom class, but first let us briefly look at how to monitor changes to the network connection state.
The NetworkChange.NetworkAddressChanged
event is raised if the IP address of the phone changes, which typically happens when any of the following events occur:
The device connects to, or disconnects from, a Wi-Fi or mobile network.
The phone is linked to the PC via the Zune software or the Windows Phone Connect Tool.
The phone is unlinked from the PC when either the Zune software or the Windows Phone Connect Tool is closed, or when the USB cable is disconnected.
Note
When linked to a PC with no Internet connection present (via the Zune software or Windows Phone Connect Tool), the phone device does not automatically switch to an available Wi-Fi connection.
When the phone switches connections, the NetworkAddressChanged
event may be raised several times. This can be troublesome if your event handler performs some expensive task. To remedy this, the custom NetworkConnectionMonitor
class, provided in the downloadable sample code, uses Reactive Extensions (Rx) to sample the event so that, at most, only one NetworkAddressChanged
event is raised each second (see Listing 27.1).
When the event is handled, the NetworkConnectionMonitor.Update
method is called, which sets the network connection type and raises the NetworkConnectionMonitor.NetworkConnectionChanged
event on the UI thread.
For more information on Rx, see Chapter 17, “Building Location Aware Apps.”
public class NetworkConnectionMonitor : INetworkConnectionMonitor
{
const int sampleRateMs = 1000;
IDisposable subscription;
public event EventHandler<EventArgs> NetworkConnectionChanged;
public NetworkConnectionType NetworkConnectionType { get; private set; }
public bool Connected
{
get
{
return NetworkConnectionType != NetworkConnectionType.None;
}
}
public NetworkConnectionMonitor()
{
Update();
var observable
= Observable.FromEvent<NetworkAddressChangedEventHandler, EventArgs>(
handler => new NetworkAddressChangedEventHandler(handler),
handler => NetworkChange.NetworkAddressChanged += handler,
handler => NetworkChange.NetworkAddressChanged -= handler);
IObservable<IEvent<EventArgs>> sampler
= observable.Sample(TimeSpan.FromMilliseconds(sampleRateMs));
subscription = sampler.ObserveOn(Scheduler.ThreadPool).Subscribe(
args => Update());
}
void Update()
{
switch (NetworkInterface.NetworkInterfaceType)
{
case NetworkInterfaceType.None:
NetworkConnectionType = NetworkConnectionType.None;
break;
case NetworkInterfaceType.MobileBroadbandCdma:
case NetworkInterfaceType.MobileBroadbandGsm:
NetworkConnectionType = NetworkConnectionType.MobileBroadband;
break;
/* These values do not apply to Windows Phone. */
case NetworkInterfaceType.AsymmetricDsl:
case NetworkInterfaceType.Atm:
/* Content omitted. */
/* Phone values */
case NetworkInterfaceType.Ethernet:
case NetworkInterfaceType.Wireless80211:
default:
NetworkConnectionType = NetworkConnectionType.Lan;
break;
}
Deployment.Current.Dispatcher.BeginInvoke(new Action(
() => NetworkConnectionChanged.Raise(this, EventArgs.Empty)));
}
}
The custom NetworkConnectionMonitor
class does not expose a NetworkInterfaceType
property, because only three values apply to the phone. Instead, it uses a custom enum type called NetworkConnectionType
, which provides a simplified view on the type of connection, with the following three values:
None—Indicates that no network connection is established
Lan—Indicates that a connection to a local area network is established, and that the app can probably be more indulgent with the amount of data it transfers
MobileBroadband—Indicates that the phone is using a cellular network, and that data usage should be used more sparingly, if at all
To use the NetworkConnectionMonitor
, define it as a field in your class and subscribe to the NetworkConnectionChanged
event, as shown:
readonly INetworkConnectionMonitor networkConnectionMonitor;
public YourViewModel()
{
networkConnectionMonitor = new NetworkConnectionMonitor();
networkConnectionMonitor.NetworkConnectionChanged
+= delegate
{
WebServiceAvailable = networkConnectionMonitor.Connected;
CanPerformDownloadLargeFile
= networkConnectionMonitor.NetworkConnectionType
== NetworkConnectionType.Lan;
};
}
Alternatively, an implementation of the INetworkConnectionMonitor
can be passed to the viewmodel, allowing it to be replaced with a mock for unit testing. This is demonstrated later in this chapter.
3.17.142.69