アプリに非同期コードを含める場合は、再入を検討し、場合によっては防止する必要があります。これは、非同期操作を完了する前に再入力することを指します。 再入の可能性を特定して処理しないと、予期しない結果が発生する可能性があります。
注
この例を実行するには、Visual Studio 2012 以降と .NET Framework 4.5 以降がコンピューターにインストールされている必要があります。
注
トランスポート層セキュリティ (TLS) バージョン 1.2 が、アプリ開発で使用する最小バージョンになりました。 アプリが 4.7 より前のバージョンの .NET Framework を対象とする場合は、 .NET Framework でのトランスポート層セキュリティ (TLS) のベスト プラクティスに関する次の記事を参照してください。
再入の認識
このトピックの例では、ユーザーが [スタート ] ボタンを選択して、一連の Web サイトをダウンロードし、ダウンロードされた合計バイト数を計算する非同期アプリを開始します。 この例の同期バージョンでは、ユーザーがボタンを選択した回数に関係なく、同じように応答します。これは、UI スレッドが最初に行った後、アプリの実行が完了するまでそれらのイベントを無視するためです。 ただし、非同期アプリでは、UI スレッドは応答を続け、完了する前に非同期操作を再入力できます。
次の例は、ユーザーが [ スタート ] ボタンを 1 回だけ選択した場合の予想される出力を示しています。 ダウンロードした 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 プロジェクトを実行するか、このトピックの最後のコードを使用して独自のプロジェクトを作成します。詳細と手順については、「 サンプル アプリの確認と実行」を参照してください。
再入の処理
アプリの実行内容に応じて、さまざまな方法で再入を処理できます。 このトピックでは、次の例を示します。
-
ユーザーが操作を中断できないように、操作の実行中に [開始] ボタンを無効にします。
-
ユーザーが [ 開始 ] ボタンをもう一度選択したときに実行中の操作をすべて取り消し、最後に要求された操作を続行します。
-
要求されたすべての操作を非同期的に実行できるようにしますが、各操作の結果が順番に一緒に表示されるように出力の表示を調整します。
スタート ボタンを無効にする
StartButton_Click
イベント ハンドラーの上部にあるボタンを無効にすると、操作の実行中に [開始] ボタンをブロックできます。 その後、操作が完了したときに Finally
ブロック内からボタンを再び有効にして、ユーザーがアプリを再度実行できるようにします。
次のコードは、アスタリスクでマークされているこれらの変更を示しています。 このトピックの最後にあるコードに変更を追加することも、 .NET Desktop Apps の Async Samples: Reentrancy から完成したアプリをダウンロードすることもできます。 プロジェクト名は 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 サイトをダウンロードしているときにボタンが応答しないため、プロセスを再入力できません。
操作を取り消して再起動する
[スタート] ボタンを無効にするのではなく、ボタンをアクティブな状態に保つことができますが、ユーザーがそのボタンをもう一度選択した場合は、既に実行されている操作を取り消し、最後に開始した操作を続行します。
キャンセルの詳細については、「 非同期アプリケーションFine-Tuning (Visual Basic)」を参照してください。
このシナリオを設定するには、「 サンプル アプリの確認と実行」で提供されている基本的なコードに次の変更を加えます。 完成したアプリは、 .NET Desktop Apps の Async Samples: Reentrancy からダウンロードすることもできます。 このプロジェクトの名前は 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
はCancellationToken引数を受け入れるため、GetAsyncメソッドを使用して Web サイトをダウンロードします。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
このアプリの実行中に [ スタート] ボタンを複数回選択すると、次の出力のような結果が生成されます。
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 番目の例は、ユーザーが [ スタート ] ボタンを選択するたびにアプリが別の非同期操作を開始し、すべての操作が完了するまで実行されるという点で最も複雑です。 要求されたすべての操作は、リストから Web サイトを非同期的にダウンロードしますが、操作からの出力は順番に表示されます。 つまり、「 再入の認識 」の出力に示されているように、実際のダウンロード アクティビティはインターリーブされますが、各グループの結果の一覧は個別に表示されます。
操作は、表示プロセスのゲートキーパーとして機能するグローバル Task ( pendingWork
) を共有します。
この例を実行するには、「 アプリのビルド」のコードに変更を貼り付けるか、「 アプリのダウンロード 」の手順に従ってサンプルをダウンロードし、QueueResults プロジェクトを実行します。
次の出力は、ユーザーが [ スタート ] ボタンを 1 回だけ選択した場合の結果を示しています。 文字ラベル A は、 最初に [スタート] ボタンが選択された時点からの結果であることを示します。 この数値は、ダウンロード ターゲットの一覧の 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.
ユーザーが [スタート ] ボタンを 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.
グループ A が終了する前にグループ B と C が開始されますが、各グループの出力は個別に表示されます。 グループ A のすべての出力が最初に表示され、次にグループ B のすべての出力が表示され、次にグループ C のすべての出力が表示されます。アプリは常にグループを順番に表示し、各グループに対して、URL が URL の一覧に表示される順序で個々の Web サイトに関する情報を常に表示します。
ただし、ダウンロードが実際に行われる順序を予測することはできません。 複数のグループが開始されると、生成されるダウンロード タスクはすべてアクティブになります。 B-1 より前に A-1 がダウンロードされるとは想定できません。また、A-1 が A-2 より前にダウンロードされるとは想定できません。
グローバル定義
サンプル コードには、すべてのメソッドから表示される次の 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
、ユーザーが [スタート ] ボタンを選択するたびにグループ文字がインクリメントされます。 その後、ハンドラーは 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
は、AccessTheWebAsync
でpendingWork
に割り当てられているタスクを返します。 この値により、タスクが完了する前に別の操作による中断が防止されます。
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
pendingWork
タスクは、最初に開始されたグループ A に対してのみ、FinishOneGroupAsync
の開始時にNothing
されます。 グループ A は、FinishOneGroupAsync
に達したときに 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 以降がコンピューターにインストールされている必要があります。
アプリのダウンロード
.NET Desktop Apps での非同期サンプル: 再入から圧縮ファイルをダウンロードします。
ダウンロードしたファイルを展開し、Visual Studio を起動します。
メニュー バーで、[ ファイル]、[ 開く]、[ プロジェクト/ソリューション] の順に選択します。
展開されたサンプル コードを保持しているフォルダーに移動し、ソリューション (.sln) ファイルを開きます。
ソリューション エクスプローラーで、実行するプロジェクトのショートカット メニューを開き、[スタートアップ プロジェクトとして設定] を選択します。
Ctrl キーを押しながら F5 キーを押して、プロジェクトをビルドして実行します。
アプリのビルド
次のセクションでは、WPF アプリとして例をビルドするコードを示します。
WPF アプリをビルドするには
Visual Studio を起動します。
メニュー バーで、 [ファイル] 、 [新規作成] 、 [プロジェクト] の順にクリックします。
[ 新しいプロジェクト ] ダイアログ ボックスが開きます。
[インストールされているテンプレート] ウィンドウで、[Visual Basic] を展開し、[Windows] を展開します。
プロジェクトの種類の一覧で、[ WPF アプリケーション] を選択します。
プロジェクトに
WebsiteDownloadWPF
名前を付け、.NET Framework バージョン 4.6 以降を選択し、[ 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 キーを押してプログラムを実行し、[ スタート ] ボタンを数回選択します。
[開始] ボタンの無効化、操作の取り消しと再起動、または [複数の操作の実行] から変更を行い、出力をキューに入れ、再入を処理します。
こちらも参照ください
.NET