次の方法で共有


Async Apps での再入の処理 (Visual Basic)

アプリに非同期コードを含める場合は、再入を検討し、場合によっては防止する必要があります。これは、非同期操作を完了する前に再入力することを指します。 再入の可能性を特定して処理しないと、予期しない結果が発生する可能性があります。

この例を実行するには、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 です。

  1. すべてのメソッドのスコープ内にある CancellationTokenSource 変数 ( cts) を宣言します。

    Class MainWindow // Or Class MainPage
    
        ' *** Declare a System.Threading.CancellationTokenSource.
        Dim cts As CancellationTokenSource
    
  2. StartButton_Clickで、操作が既に進行中かどうかを判断します。 ctsの値がNothingの場合、操作は既にアクティブでありません。 値が Nothingされていない場合、既に実行されている操作は取り消されます。

    ' *** If a download process is already underway, cancel it.
    If cts IsNot Nothing Then
        cts.Cancel()
    End If
    
  3. ctsを、現在のプロセスを表す別の値に設定します。

    ' *** Now set cts to cancel the current process if the button is chosen again.
    Dim newCTS As CancellationTokenSource = New CancellationTokenSource()
    cts = newCTS
    
  4. 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からのキャンセル トークンを受け入れるパラメーターを追加します。

  • GetAsyncCancellationToken引数を受け入れるため、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は、AccessTheWebAsyncpendingWorkに割り当てられているタスクを返します。 この値により、タスクが完了する前に別の操作による中断が防止されます。

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 以降がコンピューターにインストールされている必要があります。

アプリのダウンロード

  1. .NET Desktop Apps での非同期サンプル: 再入から圧縮ファイルをダウンロードします。

  2. ダウンロードしたファイルを展開し、Visual Studio を起動します。

  3. メニュー バーで、[ ファイル]、[ 開く]、[ プロジェクト/ソリューション] の順に選択します。

  4. 展開されたサンプル コードを保持しているフォルダーに移動し、ソリューション (.sln) ファイルを開きます。

  5. ソリューション エクスプローラーで、実行するプロジェクトのショートカット メニューを開き、[スタートアップ プロジェクトとして設定] を選択します。

  6. Ctrl キーを押しながら F5 キーを押して、プロジェクトをビルドして実行します。

アプリのビルド

次のセクションでは、WPF アプリとして例をビルドするコードを示します。

WPF アプリをビルドするには
  1. Visual Studio を起動します。

  2. メニュー バーで、 [ファイル][新規作成][プロジェクト] の順にクリックします。

    [ 新しいプロジェクト ] ダイアログ ボックスが開きます。

  3. [インストールされているテンプレート] ウィンドウで、[Visual Basic] を展開し、[Windows] を展開します。

  4. プロジェクトの種類の一覧で、[ WPF アプリケーション] を選択します。

  5. プロジェクトに WebsiteDownloadWPF名前を付け、.NET Framework バージョン 4.6 以降を選択し、[ OK ] ボタンをクリックします。

    ソリューション エクスプローラーに新しいプロジェクトが表示されます。

  6. Visual Studio コード エディターで、 [MainWindow.xaml] タブをクリックします。

    タブが表示されない場合は、 ソリューション エクスプローラーで MainWindow.xaml のショートカット メニューを開き、[ コードの表示] を選択します。

  7. 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 の デザイン ビューに表示されます。

  8. ソリューション エクスプローラーで、[参照] を右クリックし、[参照の追加] を選択します。

    まだ選択されていない場合は、 System.Net.Httpの参照を追加します。

  9. ソリューション エクスプローラーで MainWindow.xaml.vb のショートカット メニューを開き、 [コードの表示] を選択します。

  10. 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
    
  11. Ctrl + F5 キーを押してプログラムを実行し、[ スタート ] ボタンを数回選択します。

  12. [開始] ボタンの無効化、操作の取り消しと再起動、または [複数の操作の実行] から変更を行い、出力をキューに入れ、再入を処理します。

こちらも参照ください