Windows Phone のネットワーク変更を検出する方法
2013/03/11
対象: Windows Phone 8 | Windows Phone OS 7.1
作成する Windows Phone アプリで、利用可能なネットワークが変化したときにそのことを認識できるようにしたい場合があります。この変化は、アプリが既知の Wi-Fi ネットワークの圏内に入ったときなどに生じます。そのネットワークが利用可能になると、アプリでその高帯域幅のネットワーク インターフェイスを通信に活用できます。NetworkAvailabilityChanged イベントの登録により、ネットワーク可用性の変化をリッスンできます。このトピックでは、このイベントの登録方法と、イベント発生時にネットワークの変化を解釈する方法について説明します。
このトピックは、次のセクションで構成されています。
このセクションでは、ネットワーク可用性の変化を受信および表示する方法を示す UI を作成します。アプリは、起動後に、利用可能なすべてのネットワーク インターフェイスを一覧表示します。また、ネットワーク可用性の変化の通知を受信するためのサブスクライブも行います。変化が生じると、NetworkAvailabilityChanged イベントが発生します。このアプリはこのイベントを処理して、変化内容を UI のリスト上に文字列として出力します。またネットワーク設定を手動でオン/オフするための ConnectionSettingsTask を起動する方法も提供します。
アプリの UI を作成するには
Visual Studio で、[ファイル] メニューの [新しいプロジェクト] をクリックして新しいプロジェクトを作成します。
[新しいプロジェクト] ウィンドウが表示されます。[Visual C#] のテンプレートを展開し、[Windows Phone] のテンプレートを選択します。
[Windows Phone アプリ ] テンプレートを選択します。[名前] に選択した名前を入力します。
[OK] をクリックします。新しいプロジェクトが作成され、Visual Studio のデザイナー ウィンドウに MainPage.xaml が表示されます。
MainPage.xaml の中で、"LayoutRoot" という名前の Grid の XAML コードを削除し、次に示すコードで置き換えます。
<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>
上記の XAML コードでは、次のスクリーンショットのような簡単なユーザー インターフェイスが作成されます。

この UI は 4 つの部分に分かれています。画面の上部に、利用可能なネットワーク インターフェイスがすべて表示されます。このデータは NetworkInterfaceList コレクションから取得され、これはアプリが起動したときと、その後アプリが NetworkAvailabilityChanged イベントを受信するたびに読み込まれます。画面の次のセクションには、アプリが受信したすべての NetworkAvailabilityChanged イベントに関する情報が表示されます。画面の次の部分には、デバイスのネットワーク機能の全体的な状態が表示されます。さらに、ConnectionSettingsTask を起動するためのボタンが画面の下部に配置されます。このボタンは、ネットワーク設定を手動で変更し、NetworkAvailabilityChanged イベントを発生させるために使用されます。この UI の基になるコードについては、以降のセクションで説明します。
ネットワーク可用性の変化を検出するために、アプリは NetworkAvailabilityChanged イベントの登録を行います。
ネットワーク可用性の変化の登録を行うには
MainPage の分離コード ファイルを開き、次の using ディレクティブをページの先頭に追加します。
using System.Collections.ObjectModel; using Microsoft.Phone.Net.NetworkInformation; using Microsoft.Phone.Tasks;
次の変数宣言を MainPage クラスの先頭に追加します。
// 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; }
分離コード クラスの MainPage コンストラクターを次のコードに置き換えます。このメソッドはページを初期化し、前の手順で宣言したリストに UI をバインドして、NetworkAvailabilityChanged イベントをサブスクライブします。このイベントのコールバック メソッドは ChangeDetected として定義します (これについては、次の手順で説明します)。最後に、2 つのメソッドを呼び出して UI の [Network Interfaces] 領域と [Networking Status] 領域を初期化します。これらのメソッドは、以降の手順で定義します。これで、ネットワーク可用性の変化に対する登録を終えました。次のセクションでは、検出された変化を解釈する方法について説明します。
// 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(); }
前のセクションでは、NetworkAvailabilityChanged イベントの登録を行いました。その登録時に定義したコールバックは、変更の検出時に呼び出されます。このセクションでは、そのコールバック メソッドで受信したデータの処理方法について説明します。
ネットワーク可用性の変化を処理するには
分離コード ファイルに次のメソッドを追加します。これは、NetworkAvailabilityChangedNetworkAvailabilityChanged イベントをサブスクライブしたときに指定したコールバック メソッドです。NetworkNotificationEventArgs パラメーターには、通知を受けている変化に関係するすべての情報が含まれます。この例では、検出された変化の種類と、この変化が発生したインターフェイスの名前および種類をユーザーに通知する情報文字列を生成します。この情報文字列は、UI の [Events] 領域にバインドされた Changes リストに追加します。その結果、この文字列が追加されると、UI の [Events] 領域がこの追加情報で即座に更新されます。UI のネットワーク インターフェイス リストとネットワーク状態の領域も、この時点で更新されます。これらは UI 対話であり、イベントは UI スレッドで発生しないため、これらの UI 対話を BeginInvoke にラップし、UI スレッドで実行されるようにします。これに失敗すると、アプリでスレッド間の違反例外が発生します。
// 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(); }); }
MainPage クラスに次のメソッドを追加します。これらのメソッドは UI の [Network Interfaces] 領域と [Networking Status] 領域を更新します。これらは、アプリの起動時とネットワーク可用性が変化するたびに呼び出されます。UpdateNetworkInterfaces は NetworkInterfaceList オブジェクトをインスタンス化して、このクラスのクラス レベル スコープで定義した NetworkInterfaces リストにデータを挿入します。UI の [ネットワーク インターフェイス] 領域はこのリストにバインドされており、このリストは ObservableCollection<T> であるため、UI はこれらの変更が発生するとすぐにその内容で更新されます。UpdateNetworkStatus メソッドは DeviceNetworkInformation オブジェクトで静的プロパティを使用して UI の [Networking Status] 領域を更新します。これらはブール値ですが、わかりやすいように、これらのインラインを単純な "Yes" と "No" という文字列に変換しています。boolean から string への typeconverter を使用する方法もあります。
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"; }
このセクションでは、アプリで NetworkAvailabilityChanged イベントを発生させるために、ネットワークを変更する方法について説明します。ここでは、ConnectionSettingsTask を使用してデバイスの AirplaneMode のオンとオフを切り替えます。その後アプリのメイン ページに戻って、画面のイベント部分で変化を確認します。ネットワークの変更を示すこの方法には制限があります。特に、ConnectionSettingsTask の起動により、アプリがバックグラウンドに置かれます。アプリケーションがバックグラウンドにある間、イベントは受信されず、アプリに戻ると、フォアグラウンドに戻ります。つまり、ネットワーク可用性の変化がキャッチされないときがあるということです。しかしこの方法は、アプリの動作を確認するには十分です。実用されるアプリのネットワークの変化は、Wi-Fi 接続が接続および切断されたとき、ネットワーク接続の圏内から出たとき、接続の特性が変わったときに発生します。ネットワーク特性の変化の例として、携帯ネットワークでローミングするときが挙げられます。
重要: |
|---|
このアプリは、エミュレーターではなく物理デバイスでテストすることをお勧めします。エミュレーターではこれらのイベントが生成されないためです。したがって、USB 接続を使用して物理デバイスをデスクトップに接続したうえでデバッグしてください。 |
アプリをテストするには
アプリの MainPage の分離コード ファイルに以下のイベント ハンドラーを追加します。このメソッドは、フライト モードの ConnectionSettingsTask を起動します。フライト モードのオンとオフは、このタスクを使用して切り替えることができます。フライト モードがオンになると、すべてのネットワーク接続がオフになります。フライト モードがオフになると、すべてのネットワーク接続が元に戻ります。このメソッドを使用して、フライト モードの設定を変更し、アプリに戻って、フライト モードの変更によるネットワーク可用性の変化を確認できます。
// 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. }
[デバッグ]、[デバッグ開始] (F5) の順にメニュー コマンドを選択してアプリを実行します。アプリが起動し、現在利用可能なネットワーク インターフェイスが UI の [Network Interfaces] 領域に表示されます。ネットワークの現在の状態も UI の [Network Interfaces] 領域に表示されます。
物理デバイスを使用している場合は、Wi-Fi ネットワークを物理的にオフにする、ネットワークの圏外に出る、デスクトップなどへのテザリングを行っている場合は USB 接続からデバイスを切断する、という一連の手順で、ネットワークの変化を開始できます。または、アプリの [ネットワーク設定の変更] ボタンを押して ConnectionSettingsTask を起動することもできます。フライト モードのオンとオフを切り替え、デバイス ハードウェアの戻るボタンを使用して、フライト モードの切り替えの後、できるだけ早くアプリに戻ります。
ネットワーク利用可能性の変化が発生すると、アプリのイベント部分でそれを確認することができます。変化が受信されるたびに、[Network Interfaces] 領域と [Networking Status] 領域も更新されます。
ヒント: フライト モード以外でテストしたい場合は、ConnectionSettingsTask を起動するためのコードを Cellular や Wi-Fi などに設定することもできます。
重要: