非同期アプリにおける再入の処理 (Visual Basic)
非同期コードをアプリに含める場合は、再入を考慮し、場合によっては回避することをお勧めします。これは、完了前に非同期操作の再入力を参照します。 再入の可能性を特定して処理しないと、予期しない結果が発生する可能性があります。
注意
この例を実行するには、Visual Studio 2012 以降と .NET Framework 4.5 以降が、コンピューターにインストールされている必要があります。
注意
現在、アプリ開発で使用する最小バージョンは、トランスポート層セキュリティ (TLS) バージョン 1.2 です。 ご利用のアプリがバージョン 4.7 より前の .NET Framework を対象としている場合は、「.NET Framework でのトランスポート層セキュリティ (TLS) のベスト プラクティス」の記事を参照してください。
再入を認識する
このトピックの例では、ユーザーが [Start] をクリックして非同期アプリを開始します。このアプリは、一連の Web サイトをダウンロードし、ダウンロードされた合計バイト数を計算します。 同期バージョンの例では、ユーザーが何回ボタンをクリックしても同じように応答します。2 回目以降はアプリが実行を完了するまで、UI スレッドはこれらのイベントを無視するからです。 ただし、非同期アプリでは、UI スレッドは応答し続けるので、完了前に非同期操作を再入力することがあります。
次の例は、ユーザーが 1 度だけ [Start] をクリックした場合の出力を示しています。 ダウンロードされた Web サイトの一覧には、各サイトのサイズがバイト単位で表示されます。 合計バイト数は最後に表示されます。
1. msdn.microsoft.com/library/hh191443.aspx 83732
2. msdn.microsoft.com/library/aa578028.aspx 205273
3. msdn.microsoft.com/library/jj155761.aspx 29019
4. msdn.microsoft.com/library/hh290140.aspx 117152
5. msdn.microsoft.com/library/hh524395.aspx 68959
6. msdn.microsoft.com/library/ms404677.aspx 197325
7. msdn.microsoft.com 42972
8. msdn.microsoft.com/library/ff730837.aspx 146159
TOTAL bytes returned: 890591
ただし、ユーザーがボタンを複数回クリックすると、イベント ハンドラーは繰り返し呼び出され、ダウンロード プロセスはそのたびに再入力されます。 その結果、複数の非同期操作が同時に実行され、出力は結果をインターリーブするので、合計バイト数がややこしくなります。
1. msdn.microsoft.com/library/hh191443.aspx 83732
2. msdn.microsoft.com/library/aa578028.aspx 205273
3. msdn.microsoft.com/library/jj155761.aspx 29019
4. msdn.microsoft.com/library/hh290140.aspx 117152
5. msdn.microsoft.com/library/hh524395.aspx 68959
1. msdn.microsoft.com/library/hh191443.aspx 83732
2. msdn.microsoft.com/library/aa578028.aspx 205273
6. msdn.microsoft.com/library/ms404677.aspx 197325
3. msdn.microsoft.com/library/jj155761.aspx 29019
7. msdn.microsoft.com 42972
4. msdn.microsoft.com/library/hh290140.aspx 117152
8. msdn.microsoft.com/library/ff730837.aspx 146159
TOTAL bytes returned: 890591
5. msdn.microsoft.com/library/hh524395.aspx 68959
1. msdn.microsoft.com/library/hh191443.aspx 83732
2. msdn.microsoft.com/library/aa578028.aspx 205273
6. msdn.microsoft.com/library/ms404677.aspx 197325
3. msdn.microsoft.com/library/jj155761.aspx 29019
4. msdn.microsoft.com/library/hh290140.aspx 117152
7. msdn.microsoft.com 42972
5. msdn.microsoft.com/library/hh524395.aspx 68959
8. msdn.microsoft.com/library/ff730837.aspx 146159
TOTAL bytes returned: 890591
6. msdn.microsoft.com/library/ms404677.aspx 197325
7. msdn.microsoft.com 42972
8. msdn.microsoft.com/library/ff730837.aspx 146159
TOTAL bytes returned: 890591
このトピックの最後にスクロールすると、この出力を生成するコードをレビューできます。 コードを試してみるには、ソリューションをローカル コンピューターにダウンロードにし、WebsiteDownload プロジェクトを実行するか、このトピックの最後にあるコードを使用して独自のプロジェクトを作成します。詳細と手順については、「例のアプリをレビューして実行する」を参照してください。
再入を処理する
再入の処理は、アプリで何を行うかに応じてさまざまな方法で実行できます。 このトピックでは、次の例を紹介します。
-
処理の実行中、ユーザーが中断できないように [Start] ボタンを無効にします。
-
ユーザーが [Start] を再度クリックしたときに実行されている処理を取り消し、最後に要求された処理を続行できるようにします。
-
要求されたすべての処理を非同期的に実行できるようにします。ただし、各処理の結果が順番にまとめて表示されるように出力を調整します。
[Start] ボタンを無効にする
処理の実行中に [Start] ボタンを利用できないようにするには、StartButton_Click
イベント ハンドラーの上部にあるボタンを無効にします。 処理が完了しユーザーが再度アプリを実行できるようになったら、Finally
ブロック内からこのボタンを再度有効にできます。
次のコードはこの変更を示しています。変更の部分にはアスタリスクが付いています。 この変更をこのトピックの最後にあるコードに追加できます。また、完成したアプリを「Async Samples: Reentrancy in .NET Desktop Apps」 (非同期の例: .NET デスクトップ アプリでの再入) からダウンロードします。 プロジェクト名は DisableStartButton です。
Private Async Sub StartButton_Click(sender As Object, e As RoutedEventArgs)
' This line is commented out to make the results clearer in the output.
'ResultsTextBox.Text = ""
' ***Disable the Start button until the downloads are complete.
StartButton.IsEnabled = False
Try
Await AccessTheWebAsync()
Catch ex As Exception
ResultsTextBox.Text &= vbCrLf & "Downloads failed."
' ***Enable the Start button in case you want to run the program again.
Finally
StartButton.IsEnabled = True
End Try
End Sub
変更の結果、AccessTheWebAsync
が Web サイトをダウンロードしている間は、ボタンが応答しないので、プロセスを再入力できません。
操作を取り消して再開する
[Start] ボタンを無効にせず、有効の状態を保持できますが、ユーザーがボタンを再度クリックしたときに、実行中の処理を取り消し、最後に開始された処理を続行できます。
取り消しの詳細については、「非同期アプリケーションの微調整 (Visual Basic)」を参照してください。
このシナリオを設定するには、「例のアプリをレビューして実行する」に用意されている基本コードを次のように変更します。 また、完成したアプリを「Async Samples: Reentrancy in .NET Desktop Apps」 (非同期の例: .NET デスクトップ アプリでの再入) からダウンロードします。 このプロジェクトの名前は CancelAndRestart です。
すべてのメソッドのスコープである CancellationTokenSource 変数、
cts
を宣言します。Class MainWindow // Or Class MainPage ' *** Declare a System.Threading.CancellationTokenSource. Dim cts As CancellationTokenSource
StartButton_Click
で、処理が既に実行されているかどうかを確認します。cts
の値がNothing
の場合、アクティブな操作はまだありません。 値がNothing
以外の場合は、実行中の処理が取り消されます。' *** If a download process is already underway, cancel it. If cts IsNot Nothing Then cts.Cancel() End If
cts
に、現在のプロセスを表す別の値を設定します。' *** Now set cts to cancel the current process if the button is chosen again. Dim newCTS As CancellationTokenSource = New CancellationTokenSource() cts = newCTS
StartButton_Click
の最後で現在のプロセスが完了します。したがって、cts
の値をNothing
に戻します。' *** When the process completes, signal that another process can proceed. If cts Is newCTS Then cts = Nothing End If
次のコードは、StartButton_Click
のすべての変更を示しています。 追加部分はアスタリスクが付いています。
Private Async Sub StartButton_Click(sender As Object, e As RoutedEventArgs)
' This line is commented out to make the results clearer.
'ResultsTextBox.Text = ""
' *** If a download process is underway, cancel it.
If cts IsNot Nothing Then
cts.Cancel()
End If
' *** Now set cts to cancel the current process if the button is chosen again.
Dim newCTS As CancellationTokenSource = New CancellationTokenSource()
cts = newCTS
Try
' *** Send a token to carry the message if the operation is canceled.
Await AccessTheWebAsync(cts.Token)
Catch ex As OperationCanceledException
ResultsTextBox.Text &= vbCrLf & "Download canceled." & vbCrLf
Catch ex As Exception
ResultsTextBox.Text &= vbCrLf & "Downloads failed."
End Try
' *** When the process is complete, signal that another process can proceed.
If cts Is newCTS Then
cts = Nothing
End If
End Sub
AccessTheWebAsync
で、次の変更を行います。
StartButton_Click
からキャンセル トークンを受け取るためのパラメーターを追加します。GetAsync メソッドを使用して Web サイトをダウンロードします。これは
GetAsync
が CancellationToken 引数を受け取るからです。DisplayResults
を呼び出してダウンロードした各 Web サイトの結果を表示する前に、ct
で、現在の処理が取り消されていないことを確認します。
次のコードはこの変更を示しています。変更の部分にはアスタリスクが付いています。
' *** Provide a parameter for the CancellationToken from StartButton_Click.
Private Async Function AccessTheWebAsync(ct As CancellationToken) As Task
' Declare an HttpClient object.
Dim client = New HttpClient()
' Make a list of web addresses.
Dim urlList As List(Of String) = SetUpURLList()
Dim total = 0
Dim position = 0
For Each url In urlList
' *** Use the HttpClient.GetAsync method because it accepts a
' cancellation token.
Dim response As HttpResponseMessage = Await client.GetAsync(url, ct)
' *** Retrieve the website contents from the HttpResponseMessage.
Dim urlContents As Byte() = Await response.Content.ReadAsByteArrayAsync()
' *** Check for cancellations before displaying information about the
' latest site.
ct.ThrowIfCancellationRequested()
position += 1
DisplayResults(url, urlContents, position)
' Update the total.
total += urlContents.Length
Next
' Display the total count for all of the websites.
ResultsTextBox.Text &=
String.Format(vbCrLf & vbCrLf & "TOTAL bytes returned: " & total & vbCrLf)
End Function
このアプリの実行中に複数回 [Start] ボタンをクリックすると、次の出力のような結果が生成されます。
1. msdn.microsoft.com/library/hh191443.aspx 83732
2. msdn.microsoft.com/library/aa578028.aspx 205273
3. msdn.microsoft.com/library/jj155761.aspx 29019
4. msdn.microsoft.com/library/hh290140.aspx 122505
5. msdn.microsoft.com/library/hh524395.aspx 68959
6. msdn.microsoft.com/library/ms404677.aspx 197325
Download canceled.
1. msdn.microsoft.com/library/hh191443.aspx 83732
2. msdn.microsoft.com/library/aa578028.aspx 205273
3. msdn.microsoft.com/library/jj155761.aspx 29019
Download canceled.
1. msdn.microsoft.com/library/hh191443.aspx 83732
2. msdn.microsoft.com/library/aa578028.aspx 205273
3. msdn.microsoft.com/library/jj155761.aspx 29019
4. msdn.microsoft.com/library/hh290140.aspx 117152
5. msdn.microsoft.com/library/hh524395.aspx 68959
6. msdn.microsoft.com/library/ms404677.aspx 197325
7. msdn.microsoft.com 42972
8. msdn.microsoft.com/library/ff730837.aspx 146159
TOTAL bytes returned: 890591
部分的なリストを削除するには、StartButton_Click
コードの先頭行のコメントを解除して、ユーザーが操作を再開するたびに、テキスト ボックスをクリアします。
複数の操作を実行して出力をキューに登録する
この 3 番目の例は、ユーザーが [Start] ボタンをクリックするたびに非同期操作が開始され、すべての操作が完了まで実行されるという点で最も複雑です。 要求されたすべての操作によって Web サイトがリストから非同期的にダウンロードされますが、操作からの出力は順次表示されます。 つまり、「再入を認識する」の出力に示されているように、実際のダウンロード アクティビティはインターリーブされますが、各グループの結果のリストは個別に表示されます。
操作は、表示プロセスのゲートキーパーとして機能するグローバル Task、pendingWork
を共有します。
この例を実行するには、変更を「アプリケーションをビルドする」のコードに貼り付けます。また、「アプリをダウンロードする」の手順に従って、サンプルをダウンロードし、QueueResults プロジェクトを実行することもできます。
次の出力は、ユーザーが 1 度だけ [Start] ボタンをクリックした場合の結果を示しています。 文字ラベル A は、 [Start] ボタンが最初にクリックされた結果であることを示しています。 数字は、ダウンロード対象の一覧における URL の順序を示しています。
#Starting group A.
#Task assigned for group A.
A-1. msdn.microsoft.com/library/hh191443.aspx 87389
A-2. msdn.microsoft.com/library/aa578028.aspx 209858
A-3. msdn.microsoft.com/library/jj155761.aspx 30870
A-4. msdn.microsoft.com/library/hh290140.aspx 119027
A-5. msdn.microsoft.com/library/hh524395.aspx 71260
A-6. msdn.microsoft.com/library/ms404677.aspx 199186
A-7. msdn.microsoft.com 53266
A-8. msdn.microsoft.com/library/ff730837.aspx 148020
TOTAL bytes returned: 918876
#Group A is complete.
ユーザーが [Start] ボタンを 3 回クリックすると、アプリでは次のような出力が生成されます。 先頭にシャープ記号 (#) が付いている情報行は、アプリケーションの進行状況を追跡します。
#Starting group A.
#Task assigned for group A.
A-1. msdn.microsoft.com/library/hh191443.aspx 87389
A-2. msdn.microsoft.com/library/aa578028.aspx 207089
A-3. msdn.microsoft.com/library/jj155761.aspx 30870
A-4. msdn.microsoft.com/library/hh290140.aspx 119027
A-5. msdn.microsoft.com/library/hh524395.aspx 71259
A-6. msdn.microsoft.com/library/ms404677.aspx 199185
#Starting group B.
#Task assigned for group B.
A-7. msdn.microsoft.com 53266
#Starting group C.
#Task assigned for group C.
A-8. msdn.microsoft.com/library/ff730837.aspx 148010
TOTAL bytes returned: 916095
B-1. msdn.microsoft.com/library/hh191443.aspx 87389
B-2. msdn.microsoft.com/library/aa578028.aspx 207089
B-3. msdn.microsoft.com/library/jj155761.aspx 30870
B-4. msdn.microsoft.com/library/hh290140.aspx 119027
B-5. msdn.microsoft.com/library/hh524395.aspx 71260
B-6. msdn.microsoft.com/library/ms404677.aspx 199186
#Group A is complete.
B-7. msdn.microsoft.com 53266
B-8. msdn.microsoft.com/library/ff730837.aspx 148010
TOTAL bytes returned: 916097
C-1. msdn.microsoft.com/library/hh191443.aspx 87389
C-2. msdn.microsoft.com/library/aa578028.aspx 207089
#Group B is complete.
C-3. msdn.microsoft.com/library/jj155761.aspx 30870
C-4. msdn.microsoft.com/library/hh290140.aspx 119027
C-5. msdn.microsoft.com/library/hh524395.aspx 72765
C-6. msdn.microsoft.com/library/ms404677.aspx 199186
C-7. msdn.microsoft.com 56190
C-8. msdn.microsoft.com/library/ff730837.aspx 148010
TOTAL bytes returned: 920526
#Group C is complete.
グループ B とグループ C は、グループ A が終了する前に開始します。ただし、各グループの出力は個別に表示されます。 グループ A のすべての出力が最初に表示され、その後にグループ B のすべての出力が続き、さらにグループ C のすべての出力が表示されます。グループは必ず順番に表示され、グループごとに、個別の Web サイトに関する情報が URL 一覧の URL の順番で表示されます。
ただし、ダウンロードが実際に行われる順序は予測できません。 複数のグループが開始されたら、そのグループが生成するダウンロード タスクはすべてのアクティブです。 B-1 の前に A-1 がダウンロードされる、また、A-2 の前に A-1 がダウンロードされると仮定することはできません。
グローバル定義
サンプル コードには、すべてのメソッドから参照できる次の 2 つのグローバル宣言が含まれます。
Class MainWindow ' Class MainPage in Windows Store app.
' ***Declare the following variables where all methods can access them.
Private pendingWork As Task = Nothing
Private group As Char = ChrW(AscW("A") - 1)
Task
変数、pendingWork
は、表示プロセスを監視し、あるグループが別のグループの表示操作を中断しないようにします。 文字変数 group
は、異なるグループからの出力にラベルを付け、予想された順序で結果が表示されていることを確認します。
Click イベント ハンドラー
イベント ハンドラー StartButton_Click
は、ユーザーが [Start] ボタンを選択するたびに、グループ文字をインクリメントします。 ハンドラーは AccessTheWebAsync
を呼び出して、ダウンロード操作を実行します。
Private Async Sub StartButton_Click(sender As Object, e As RoutedEventArgs)
' ***Verify that each group's results are displayed together, and that
' the groups display in order, by marking each group with a letter.
group = ChrW(AscW(group) + 1)
ResultsTextBox.Text &= String.Format(vbCrLf & vbCrLf & "#Starting group {0}.", group)
Try
' *** Pass the group value to AccessTheWebAsync.
Dim finishedGroup As Char = Await AccessTheWebAsync(group)
' The following line verifies a successful return from the download and
' display procedures.
ResultsTextBox.Text &= String.Format(vbCrLf & vbCrLf & "#Group {0} is complete." & vbCrLf, finishedGroup)
Catch ex As Exception
ResultsTextBox.Text &= vbCrLf & "Downloads failed."
End Try
End Sub
AccessTheWebAsync メソッド
この例では、AccessTheWebAsync
を 2 つのメソッドに分割します。 最初のメソッド、AccessTheWebAsync
は、グループのすべてのダウンロード タスクを開始し、pendingWork
を設定して表示プロセスを制御します。 このメソッドは、統合言語クエリ (LINQ クエリ) と ToArray を使用して、すべてのダウンロードを同時に開始します。
その後、AccessTheWebAsync
は、FinishOneGroupAsync
を呼び出して各ダウンロードが完了するまで待機し、その長さを表示します。
FinishOneGroupAsync
は、pendingWork
の AccessTheWebAsync
に割り当てられたタスクを返します。 この値は、タスクが完了する前に、別の操作によって操作が中断されないようにします。
Private Async Function AccessTheWebAsync(grp As Char) As Task(Of Char)
Dim client = New HttpClient()
' Make a list of the web addresses to download.
Dim urlList As List(Of String) = SetUpURLList()
' ***Kick off the downloads. The application of ToArray activates all the download tasks.
Dim getContentTasks As Task(Of Byte())() =
urlList.Select(Function(addr) client.GetByteArrayAsync(addr)).ToArray()
' ***Call the method that awaits the downloads and displays the results.
' Assign the Task that FinishOneGroupAsync returns to the gatekeeper task, pendingWork.
pendingWork = FinishOneGroupAsync(urlList, getContentTasks, grp)
ResultsTextBox.Text &=
String.Format(vbCrLf & "#Task assigned for group {0}. Download tasks are active." & vbCrLf, grp)
' ***This task is complete when a group has finished downloading and displaying.
Await pendingWork
' You can do other work here or just return.
Return grp
End Function
FinishOneGroupAsync メソッド
このメソッドは、グループのダウンロード タスクを循環参照し、それぞれを待機してから、ダウンロードされた Web サイトの長さを表示して、その長さを合計に追加します。
FinishOneGroupAsync
の最初のステートメントは、pendingWork
を使用して、メソッドを入力することが、表示プロセスの操作または待機中の操作の妨げにならないようにします。 これらの操作が進行中の場合、入力操作は順番を待つ必要があります。
Private Async Function FinishOneGroupAsync(urls As List(Of String), contentTasks As Task(Of Byte())(), grp As Char) As Task
' Wait for the previous group to finish displaying results.
If pendingWork IsNot Nothing Then
Await pendingWork
End If
Dim total = 0
' contentTasks is the array of Tasks that was created in AccessTheWebAsync.
For i As Integer = 0 To contentTasks.Length - 1
' Await the download of a particular URL, and then display the URL and
' its length.
Dim content As Byte() = Await contentTasks(i)
DisplayResults(urls(i), content, i, grp)
total += content.Length
Next
' Display the total count for all of the websites.
ResultsTextBox.Text &=
String.Format(vbCrLf & vbCrLf & "TOTAL bytes returned: " & total & vbCrLf)
End Function
この例を実行するには、変更を「アプリケーションをビルドする」のコードに貼り付けます。また、「アプリをダウンロードする」の手順に従って、サンプルをダウンロードし、QueueResults プロジェクトを実行することもできます。
目的のポイント
出力で先頭にシャープ記号 (#) が付いている情報行は、この例の動作を明確に示しています。
出力のパターンを次に示します。
前のグループが出力を表示していても、グループを開始できます。その際、前のグループの出力の表示は中断されません。
#Starting group A. #Task assigned for group A. Download tasks are active. A-1. msdn.microsoft.com/library/hh191443.aspx 87389 A-2. msdn.microsoft.com/library/aa578028.aspx 207089 A-3. msdn.microsoft.com/library/jj155761.aspx 30870 A-4. msdn.microsoft.com/library/hh290140.aspx 119037 A-5. msdn.microsoft.com/library/hh524395.aspx 71260 #Starting group B. #Task assigned for group B. Download tasks are active. A-6. msdn.microsoft.com/library/ms404677.aspx 199186 A-7. msdn.microsoft.com 53078 A-8. msdn.microsoft.com/library/ff730837.aspx 148010 TOTAL bytes returned: 915919 B-1. msdn.microsoft.com/library/hh191443.aspx 87388 B-2. msdn.microsoft.com/library/aa578028.aspx 207089 B-3. msdn.microsoft.com/library/jj155761.aspx 30870 #Group A is complete. B-4. msdn.microsoft.com/library/hh290140.aspx 119027 B-5. msdn.microsoft.com/library/hh524395.aspx 71260 B-6. msdn.microsoft.com/library/ms404677.aspx 199186 B-7. msdn.microsoft.com 53078 B-8. msdn.microsoft.com/library/ff730837.aspx 148010 TOTAL bytes returned: 915908
最初に開始したグループ A についてのみ、
FinishOneGroupAsync
開始時の、pendingWork
タスクはNothing
になります。FinishOneGroupAsync
に達したとき、グループ A はまだ await 式を完了していません。 したがって、コントロールはAccessTheWebAsync
に戻っておらず、pendingWork
への最初の割り当ては発生していません。次の 2 行は、出力に必ず同時に表示されます。
StartButton_Click
のグループ操作が開始してから、グループのタスクがpendingWork
に割り当てられるまでの間、コードが中断されることは決してありません。#Starting group B. #Task assigned for group B. Download tasks are active.
グループが
StartButton_Click
に移行したら、FinishOneGroupAsync
に移行するまでは、await 式は完了しません。 したがって、コード セグメントの途中で、他の操作がコントロールを得ることはありません。
例のアプリをレビューして実行する
サンプル アプリをさらに詳しく理解するには、そのアプリをダウンロードし、ご自身でビルドしてみてください。また、このトピックの最後にあるコードをレビューすることもできます。アプリを実装する必要はありません。
注意
Windows Presentation Foundation (WPF) デスクトップ アプリとして例を実行するには、Visual Studio 2012 以降と .NET Framework 4.5 以降がコンピューターにインストールされている必要があります。
アプリをダウンロードする
圧縮ファイルを「Async Samples: Reentrancy in .NET Desktop Apps」 (非同期の例: .NET デスクトップ アプリでの再入) からダウンロードします。
ダウンロードしたファイルを圧縮解除し、Visual Studio を起動します。
メニュー バーで [ファイル] 、 [開く] 、 [プロジェクト/ソリューション] の順に選択します。
圧縮解除したサンプル コードが含まれるフォルダーに移動し、ソリューション (.sln) ファイルを開きます。
ソリューション エクスプローラーで、実行するプロジェクトのショートカット メニューを開き、 [スタートアップ プロジェクトに設定] を選択します。
Ctrl キーを押しながら F5 キーを押してプロジェクトをビルドし、実行します。
アプリケーションをビルドする
次のセクションでは、WPF アプリとして例をビルドするコードを示します。
WPF アプリをビルドするには
Visual Studio を起動します。
メニュー バーで、 [ファイル] 、 [新規作成] 、 [プロジェクト] の順にクリックします。
[新しいプロジェクト] ダイアログ ボックスが表示されます。
[インストールされたテンプレート] ペインで、 [Visual Basic] を展開し、 [Windows] を展開します。
プロジェクトの種類の一覧の [WPF アプリケーション] をクリックします。
プロジェクトに
WebsiteDownloadWPF
という名前を指定し、4.6 以降の .NET Framework のバージョンを選択して、[OK] ボタンをクリックします。ソリューション エクスプローラーに新しいプロジェクトが表示されます。
Visual Studio コード エディターで、 [MainWindow.xaml] タブをクリックします。
タブが表示されない場合は、ソリューション エクスプローラーで MainWindow.xaml のショートカット メニューを開き、 [コードの表示] を選択します。
MainWindow.xaml の XAML ビューで、コードを次のコードに置き換えます。
<Window x:Class="MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:WebsiteDownloadWPF" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"> <Grid Width="517" Height="360"> <Button x:Name="StartButton" Content="Start" HorizontalAlignment="Left" Margin="-1,0,0,0" VerticalAlignment="Top" Click="StartButton_Click" Height="53" Background="#FFA89B9B" FontSize="36" Width="518" /> <TextBox x:Name="ResultsTextBox" HorizontalAlignment="Left" Margin="-1,53,0,-36" TextWrapping="Wrap" VerticalAlignment="Top" Height="343" FontSize="10" ScrollViewer.VerticalScrollBarVisibility="Visible" Width="518" FontFamily="Lucida Console" /> </Grid> </Window>
テキスト ボックスとボタンを含む簡単なウィンドウが、MainWindow.xaml のデザイン ビューに表示されます。
ソリューション エクスプローラーで [参照] を右クリックし、 [参照の追加] を選択します。
まだ選択されていない場合は、System.Net.Http の参照を追加します。
ソリューション エクスプローラーで MainWindow.xaml.vb のショートカット メニューを開き、 [コードの表示] を選択します。
MainWindow.xaml.vb のコードを次のコードに置き換えます。
' Add the following Imports statements, and add a reference for System.Net.Http. Imports System.Net.Http Imports System.Threading Class MainWindow Private Async Sub StartButton_Click(sender As Object, e As RoutedEventArgs) System.Net.ServicePointManager.SecurityProtocol = System.Net.ServicePointManager.SecurityProtocol Or System.Net.SecurityProtocolType.Tls12 ' This line is commented out to make the results clearer in the output. 'ResultsTextBox.Text = "" Try Await AccessTheWebAsync() Catch ex As Exception ResultsTextBox.Text &= vbCrLf & "Downloads failed." End Try End Sub Private Async Function AccessTheWebAsync() As Task ' Declare an HttpClient object. Dim client = New HttpClient() ' Make a list of web addresses. Dim urlList As List(Of String) = SetUpURLList() Dim total = 0 Dim position = 0 For Each url In urlList ' GetByteArrayAsync returns a task. At completion, the task ' produces a byte array. Dim urlContents As Byte() = Await client.GetByteArrayAsync(url) position += 1 DisplayResults(url, urlContents, position) ' Update the total. total += urlContents.Length Next ' Display the total count for all of the websites. ResultsTextBox.Text &= String.Format(vbCrLf & vbCrLf & "TOTAL bytes returned: " & total & vbCrLf) End Function Private Function SetUpURLList() As List(Of String) Dim urls = New List(Of String) From { "https://msdn.microsoft.com/library/hh191443.aspx", "https://msdn.microsoft.com/library/aa578028.aspx", "https://msdn.microsoft.com/library/jj155761.aspx", "https://msdn.microsoft.com/library/hh290140.aspx", "https://msdn.microsoft.com/library/hh524395.aspx", "https://msdn.microsoft.com/library/ms404677.aspx", "https://msdn.microsoft.com", "https://msdn.microsoft.com/library/ff730837.aspx" } Return urls End Function Private Sub DisplayResults(url As String, content As Byte(), pos As Integer) ' Display the length of each website. The string format is designed ' to be used with a monospaced font, such as Lucida Console or ' Global Monospace. ' Strip off the "http:'". Dim displayURL = url.Replace("https://", "") ' Display position in the URL list, the URL, and the number of bytes. ResultsTextBox.Text &= String.Format(vbCrLf & "{0}. {1,-58} {2,8}", pos, displayURL, content.Length) End Sub End Class
Ctrl キーを押しながら F5 キーを押してプログラムを実行し、 [Start] ボタンを複数回クリックします。
「[Start] ボタンを無効にする」、「操作を取り消して再開する」、または「複数の操作を実行して出力をキューに登録する」の変更を行って再入を処理します。
関連項目
.NET