Udostępnij za pośrednictwem


How to detect network changes for Windows Phone 8

[ This article is for Windows Phone 8 developers. If you’re developing for Windows 10, see the latest documentation. ]

 

When creating a Windows Phone app, you might want to know when the available networks change. This can happen when, for example, your app comes into coverage of a known Wi-Fi network. Suddenly that network becomes available, and your app has the opportunity to take advantage of this high-bandwidth network interface for communication. You can listen for network availability changes by registering for the NetworkAvailabilityChanged event. This topic describes how to register for this event and how to interpret what the network changes are when the event is fired.

This topic contains the following sections.

 

Creating the app UI

In this section, you create the UI for demonstrating how to receive and show network availability changes. When the app starts, it lists all network interfaces that are available. It also subscribes to receive notifications of network availability changes. When a change occurs, the NetworkAvailabilityChanged event fires. The app handles this event and outputs the change as a string to a list on the UI. The app also provides a way to launch the ConnectionSettingsTask in order to manually turn network settings on or off.

To create the app UI

  1. In Visual Studio, create a new project by selecting the File | New Project menu command.

  2. The New Project window is displayed. Expand the Visual C# templates, and then select the Windows Phone templates.

  3. Select the **Windows Phone App ** template. Fill in the Name with a name of your choice.

  4. Click OK. A new project is created, and MainPage.xaml is opened in the Visual Studio designer window.

  5. On MainPage.xaml, remove the XAML code for the Grid named “LayoutRoot” and replace it with the following code.

    <Grid x:Name="LayoutRoot" Background="Transparent">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
    
        <!--TitlePanel contains the name of the application and page title-->
        <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
            <TextBlock x:Name="ApplicationTitle" Text="Network Change Detector" Style="{StaticResource PhoneTextNormalStyle}"/>
        </StackPanel>
    
        <!--ContentPanel - place additional content here-->
        <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="*"/>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="Auto"/>
            </Grid.RowDefinitions>
            <TextBlock Grid.Row="0" Text="Available Network Interfaces" FontSize="{StaticResource PhoneFontSizeLarge}"/>
            <ListBox Grid.Row="1" x:Name="lbNetworkInterfaces" ItemsSource="{Binding}" Background="LightGray" >
                <ListBox.ItemTemplate>
                    <DataTemplate>
                        <TextBlock Text="{Binding}" Margin="5,5,0,5" Foreground="Black"/>
                    </DataTemplate>
                </ListBox.ItemTemplate>
            </ListBox>
            <TextBlock Grid.Row="2" Text="Events" FontSize="{StaticResource PhoneFontSizeLarge}"/>
            <ScrollViewer Grid.Row="3" Background="LightGray" BorderThickness="1">
                <ListBox x:Name="lbNetworkChanges" ItemsSource="{Binding}">
                    <ListBox.ItemTemplate>
                        <DataTemplate>
                            <TextBlock Text="{Binding}" Foreground="Black" 
                                        FontSize="{StaticResource PhoneFontSizeNormal}" TextWrapping="Wrap" Margin="5,10,0,10"  />
                        </DataTemplate>
                    </ListBox.ItemTemplate>
                </ListBox>
            </ScrollViewer>
            <TextBlock Grid.Row="4" Text="Networking Status" FontSize="{StaticResource PhoneFontSizeLarge}"/>
            <Grid Grid.Row="5" Background="LightGray" >
                <Grid.RowDefinitions>
                    <RowDefinition Height="Auto"/>
                    <RowDefinition Height="Auto"/>
                    <RowDefinition Height="Auto"/>
                </Grid.RowDefinitions>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="Auto"/>
                    <ColumnDefinition Width="*"/>
                </Grid.ColumnDefinitions>
                <TextBlock Grid.Row="0" Grid.Column="0" Text="IsNetworkAvailable" Foreground="Black" Margin="5,5,0,5" />
                <TextBlock Grid.Row="0" Grid.Column="1" x:Name="tbIsNetworkAvailable" HorizontalAlignment="Center" Foreground="Black" />
    
                <TextBlock Grid.Row="1" Grid.Column="0" Text="IsWiFiEnabled" Foreground="Black" Margin="5,5,0,5" />
                <TextBlock Grid.Row="1" Grid.Column="1" x:Name="tbIsWiFiEnabled" HorizontalAlignment="Center" Foreground="Black"/>
    
                <TextBlock Grid.Row="2" Grid.Column="0" Text="IsCellularDataEnabled" Foreground="Black" Margin="5,5,0,5" />
                <TextBlock Grid.Row="2" Grid.Column="1" x:Name="tbIsCellularDataEnabled" HorizontalAlignment="Center" Foreground="Black"/>
            </Grid>
            <Button Grid.Row="6" x:Name="btnChangeNetworkSettings" Content="Change Network Settings" Click="btnChangeNetworkSettings_Click"/>
        </Grid>
    </Grid>
    

    The preceding XAML code creates a simple user interface that looks like the following screenshot.

    The UI is broken up into four parts. At the top of the screen we display all available network interfaces. This data is retrieved from the NetworkInterfaceList collection. It is loaded when the app starts and whenever an NetworkAvailabilityChanged event is received by the app. The next section of the screen will display information about any NetworkAvailabilityChanged events that are received by the app. The next part of the screen displays the overall status of the network abilities of the device. Finally, a button is placed at the bottom of the screen to launch the ConnectionSettingsTask in order to change network settings manually and cause NetworkAvailabilityChanged events to be fired. The code that drives this UI is described in the following sections.

Registering for network availability changes

In order to detect changes to network availability, the app registers for the NetworkAvailabilityChanged event.

To register for network availability changes

  1. Open the code-behind file for your MainPage and add the following using directives to the top of the page.

    using System.Collections.ObjectModel;
    using Microsoft.Phone.Net.NetworkInformation;
    using Microsoft.Phone.Tasks;
    
  2. Add the following variable declarations to the top of the MainPage class.

    // List of all changes detected while the app is running.
    public ObservableCollection<string> Changes { get; set; }
    
    // List of all currently available network interfaces
    public ObservableCollection<string> NetworkInterfaces { get; set; }
    
  3. Replace the MainPage constructor in the code-behind class with the following code. This method initializes the page, binds the UI to the lists declared in the preceding step and subscribes to the NetworkAvailabilityChanged event. The callback method for this event is defined as ChangeDetected and this will be described in a subsequent step. Finally, it calls two methods to initialize the Network Interfaces and Networking Status areas of the UI. These methods are defined in steps that follow. We have now registered for network availability changes. The next section describes how to interpret the detected changes.

    // Constructor
    public MainPage()
    {
        InitializeComponent();
    
        // Initialise the Changes list.
        Changes = new ObservableCollection<string>();
    
        // Bind the ListBox to the Changes list
        lbNetworkChanges.DataContext = Changes;
    
        NetworkInterfaces = new ObservableCollection<string>();
        lbNetworkInterfaces.DataContext = NetworkInterfaces;
    
        // Subscribe to the NetworkAvailabilityChanged event
        DeviceNetworkInformation.NetworkAvailabilityChanged += new EventHandler<NetworkNotificationEventArgs>(ChangeDetected);
    
        UpdateNetworkInterfaces();
        UpdateNetworkStatus();
    }
    

Handling network availability changes

In the previous section, we registered for NetworkAvailabilityChanged events. Whenever a change is detected, the callback we defined when registering for this event will be called. This section describes how to handle the data received in that callback method.

To handle network availability changes

  1. In the code-behind file add the following method. This is the callback method we provided when we subscribed to the NetworkAvailabilityChanged event. The NetworkNotificationEventArgs parameter contains all the information related to the change about which we are being notified. In this example, we produce an informational string that tells the user what kind of change was detected, what the name of the interface is that experienced this change and also the type of this interface. We add this informational string to the Changes list which is bound to the Events area of the UI. As a result, as soon as this string is added, the Events area of the UI is updated with this additional information. The network interfaces list and the networking status areas of the UI are also updated at this point. Because these are UI interactions, and the event is not fired on the UI thread, we wrap the UI interactions in a BeginInvoke to make sure they are performed on the UI thread. Failure to do this would result in a cross thread violation exception in the app.

    // In this callback, we examine the change that was detected. In this example, we are 
    // creating a simple information string and adding that to the event list on the UI. 
    // In a real application, this is where you might adjust your communication connection 
    // in order to take advantage of a network availability change. 
    void ChangeDetected(object sender, NetworkNotificationEventArgs e)
    {
        string change = string.Empty;
        switch (e.NotificationType)
        {
            case NetworkNotificationType.InterfaceConnected:
                change = "Connected to ";
                break;
            case NetworkNotificationType.InterfaceDisconnected:
                change = "Disconnected from ";
                break;
            case NetworkNotificationType.CharacteristicUpdate:
                change = "Characteristics changed for ";
                break;
            default:
                change = "Unknown change with ";
                break;
        }
    
        string changeInformation = String.Format(" {0} {1} {2} ({3})",
                    DateTime.Now.ToString(), change, e.NetworkInterface.InterfaceName,
                    e.NetworkInterface.InterfaceType.ToString());
    
        // We are making UI updates, so make sure these happen on the UI thread.
        Dispatcher.BeginInvoke(() =>
        {
            Changes.Add(changeInformation);
            UpdateNetworkStatus();
            UpdateNetworkInterfaces();
    
        });
    
    }
    
  2. In the MainPage class add the following methods. These methods update the Network Interfaces and Networking Status areas of the UI. They are called when the app starts and whenever a network availability change occurs. UpdateNetworkInterfaces instantiates a NetworkInterfaceList object to populate the NetworkInterfaces list we defined at class-level scope in this class. Since the Network Interfaces area of the UI is bound to this list, and the list is an ObservableCollection<(Of <(T>)>), the UI will update with these changes as soon as they are made. The UpdateNetworkStatus method uses static properties on the DeviceNetworkInformation object to update the Networking Status area of the UI. These are boolean values, but for simplicity we convert these inline to simple “Yes” and “No” strings. An alternative approach would have been to use a boolean to stringtypeconverter.

    private void UpdateNetworkInterfaces()
    {
    
        NetworkInterfaces.Clear();
        NetworkInterfaceList networkInterfaceList = new NetworkInterfaceList();
        foreach (NetworkInterfaceInfo networkInterfaceInfo in networkInterfaceList)
        {
            NetworkInterfaces.Add(networkInterfaceInfo.InterfaceName);
        }
    }
    
    private void UpdateNetworkStatus()
    {
        tbIsCellularDataEnabled.Text = (DeviceNetworkInformation.IsCellularDataEnabled) ? "Yes" : "No";
        tbIsNetworkAvailable.Text = (DeviceNetworkInformation.IsNetworkAvailable) ? "Yes" : "No";
        tbIsWiFiEnabled.Text = (DeviceNetworkInformation.IsWiFiEnabled) ? "Yes" : "No";
    }
    

Testing the app

This section demonstrates how to cause network changes in order to make the NetworkAvailabilityChanged event fire in our app. It uses the ConnectionSettingsTask to switch AirplaneMode on and off on the device. Once this is done, you can navigate back to the main page of the app and see the resulting events in the Events area of the screen. This method of demonstrating network changes has its limitations. In particular, the launching of the ConnectionSettingsTask causes the app to be placed in the background. While in the background no events will be received. When you navigate back to the app it will be brought to the foreground. This means there is time when some network availability changes will not be caught. This method, however, is sufficient to demonstrate the behavior of the app. In a real-world app network changes will occur whenever Wi-Fi connections are connected and disconnected, whenever you move out of range of a network connection or when the characteristics of the connection change. An example of network characteristics changing is when you roam on your cellular network.

Important Note:

It is advisable to test this app on a physical device, as opposed to the emulator. This is because the emulator does not fire these events. Instead, connect a physical device to you desktop using the USB connection and debug that way.

To test the app

  1. In the code-behind file of the MainPage in the app add the following event handler. This method launches the ConnectionSettingsTask for Airplane mode. You can switch Airplane mode on and off using this task. When Airplane Mode is on, all network connections will be switched off. When Airplane mode is off, all network connections will be restored. Using this method you can change the Airplane mode setting, navigate back to the app and observe the network availability changes caused by changing the Airplane mode.

    // For testing purposes, we provide a way to change the network connection
    // settings by launching the ConnectionSettingsTask. However, because we are moving 
    // our application to the background and then to the foreground when we navigate back from
    // the ConnectionSettingTask, there is a chance we may not receive all NetworkAvailabilityChanged events.
    // Alternatively, you can test by physically disconnecting a Wi-Fi connection, by connecting and disconnecting
    // your device to your desktop, or by moving out of range of your Wi-Fi network.
    private void btnChangeNetworkSettings_Click(object sender, RoutedEventArgs e)
    {
        MessageBox.Show("This action will launch the ConnectionSettingsTask where you can change the network settings." + 
                            " As soon as you have made your changes, use the hardware Back button to get back to this page so that you can observe the NetworkAvailabilityChanged events.");
    
        //Use the ConnectionSettingsTask to bring up the connection settings
        ConnectionSettingsTask connectionSettings = new ConnectionSettingsTask();
    
        // We are using the Connection Settings page for AirplaneMode.
        connectionSettings.ConnectionSettingsType = ConnectionSettingsType.AirplaneMode;
        connectionSettings.Show();
    
        // Note: Once you have changed the settings (switched from On to Off for example)
        // use the hardward Back button on your device to go back to this page and catch
        // the NetworkAvailabilityChanged events.
    }
    
  2. Run the app by selecting the Debug|Start Debugging (F5) menu command. The app launches and the currently available network interfaces are displayed in the Network Interfaces area of the UI. The current status of networking is also displayed in the Networking Status area of the UI.

  3. If you are using a physical device, you can initiate network changes by physically switching off a Wi-Fi network, moving out of range of a network, disconnecting the device from the USB connection if tethered to your desktop and many other ways. Alternatively, you can press the Change Network Settings button on the app, which launches the ConnectionSettingsTask. Toggle Airplane Mode on or off and then use the devices hardware Back button to get back to the app as soon after you toggled the Airplane mode as possible.

  4. As network availability changes occur, you can observe them in the Events area of the app. The Network Interfaces and Networking Status areas will also be updated each time a change is received.

Tip

You can change the preceding code to launch the ConnectionSettingsTask for Cellular or Wi-Fi if you do not wish to test with Airplane Mode.

See Also

Reference

Microsoft.Phone.Net.NetworkInformation

DeviceNetworkInformation

ConnectionSettingsTask

Other Resources

Network and network interface information for Windows Phone 8