非同期アプリにおける再入の処理 (C# および Visual Basic)
独自のアプリケーションでは、非同期コードを含めると、完了する前に、非同期操作の入力し直を示す再入を検討し、場合によっては避ける必要があります。再入の可能性を指定せず、処理により、予期しない結果が生じる可能性があります。
このトピックの内容
[!メモ]
App 例を確認し、実行します。 の手順は、Windows Presentation Foundation (WPF) アプリケーションまたは Windows ストア アプリケーションとしてコードを実行する方法を示します。
WPF アプリケーションとして例を実行するには、Visual Studio 2012 Visual Studio には、Windows のデスクトップの 2012 を表します。、またはのコンピューターに .NET Framework 4.5 がインストールされている必要があります。
Windows ストア アプリケーションとして例を実行するには、コンピューターにインストールされている Windows 8 が必要です。また、Visual Studio で例を実行する場合、Visual Studio 2012 が Visual Studio には、Windows 8 の 2012 を表します。 あるインストールします。
再入の確認
このトピックの例では、ユーザーがダウンロードの一連の Web サイトがダウンロードされる合計バイト数を計算する非同期アプリケーションを起動するために [開始] のボタンを選択します。例では、同期バージョンに関係なく同じ方法でアプリケーションが実行されるまで、最初にすると、UI スレッドがそのイベントが無視されるため、数時間ユーザーがボタンを選択するか応答します。非同期アプリケーションでは、UI スレッドが応答を完了する前に非同期操作を入力する場合があります。
次の例では、ユーザーが一度だけ [開始] のボタンを選択すると予想される出力を示しています。ダウンロードされたサイトのリストは、サイズと、各サイトのサイズをバイト単位で表示されます。合計バイト数が最後に表示されます。
1. msdn.microsoft.com/en-us/library/hh191443.aspx 83732
2. msdn.microsoft.com/en-us/library/aa578028.aspx 205273
3. msdn.microsoft.com/en-us/library/jj155761.aspx 29019
4. msdn.microsoft.com/en-us/library/hh290140.aspx 117152
5. msdn.microsoft.com/en-us/library/hh524395.aspx 68959
6. msdn.microsoft.com/en-us/library/ms404677.aspx 197325
7. msdn.microsoft.com 42972
8. msdn.microsoft.com/en-us/library/ff730837.aspx 146159
TOTAL bytes returned: 890591
ただし、ユーザーがボタンを何度も選択すると、イベント ハンドラーは繰り返し呼び出され、ダウンロードのプロセスは常に入力されます。その結果、複数の非同期操作の結果、出力はインターリーブ同時に実行、合計バイト数は複雑です。
1. msdn.microsoft.com/en-us/library/hh191443.aspx 83732
2. msdn.microsoft.com/en-us/library/aa578028.aspx 205273
3. msdn.microsoft.com/en-us/library/jj155761.aspx 29019
4. msdn.microsoft.com/en-us/library/hh290140.aspx 117152
5. msdn.microsoft.com/en-us/library/hh524395.aspx 68959
1. msdn.microsoft.com/en-us/library/hh191443.aspx 83732
2. msdn.microsoft.com/en-us/library/aa578028.aspx 205273
6. msdn.microsoft.com/en-us/library/ms404677.aspx 197325
3. msdn.microsoft.com/en-us/library/jj155761.aspx 29019
7. msdn.microsoft.com 42972
4. msdn.microsoft.com/en-us/library/hh290140.aspx 117152
8. msdn.microsoft.com/en-us/library/ff730837.aspx 146159
TOTAL bytes returned: 890591
5. msdn.microsoft.com/en-us/library/hh524395.aspx 68959
1. msdn.microsoft.com/en-us/library/hh191443.aspx 83732
2. msdn.microsoft.com/en-us/library/aa578028.aspx 205273
6. msdn.microsoft.com/en-us/library/ms404677.aspx 197325
3. msdn.microsoft.com/en-us/library/jj155761.aspx 29019
4. msdn.microsoft.com/en-us/library/hh290140.aspx 117152
7. msdn.microsoft.com 42972
5. msdn.microsoft.com/en-us/library/hh524395.aspx 68959
8. msdn.microsoft.com/en-us/library/ff730837.aspx 146159
TOTAL bytes returned: 890591
6. msdn.microsoft.com/en-us/library/ms404677.aspx 197325
7. msdn.microsoft.com 42972
8. msdn.microsoft.com/en-us/library/ff730837.aspx 146159
TOTAL bytes returned: 890591
このトピックの最後にスクロールすると、この出力を生成するコードを確認できます。コードで、ローカル コンピューターにソリューションのダウンロードにしてみて、このトピックの最後にあるコードを詳細および命令について、独自のプロジェクトを作成することによって、WebsiteDownload プロジェクトを実行または App 例を確認し、実行します。"を参照してください。
再入の処理
処理するアプリケーションに必要な内容に応じて、さまざまな方法で、再入ができます。このトピックでは、次の例を示します:
-
ユーザーが中断できないように操作の実行中 [開始] のボタンを無効にします。
-
ユーザーが [開始] のボタンをもう一度選択した実行、要求された操作を続行させるに最新すると、操作をキャンセルします。
-
各操作の結果が連結と注文に表示されるすべての要求された操作が非同期的に実行されるようにしてください。ただし、出力の表示を調整します。
起動ボタンを無効にします。
操作が StartButton_Click のイベント ハンドラーの上部にあるボタンを無効にすると、実行中 [開始] のボタンをブロックできます。ユーザーがアプリケーションを再度実行できるよう、操作が完了すると、finally ブロック内でボタンを再び有効にできます。
次のコードは、アスタリスクでマークされたこれらの変更について説明します。このトピックの最後にあるコードに変更を適用したり、終了するアプリケーションを、単一の例: .NET のデスクトップ アプリケーションの再入 または 単一の例: Windows ストアの再入 Apps からダウンロードできます。プロジェクトの名前は 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
private async void StartButton_Click(object sender, RoutedEventArgs e)
{
// 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 (Exception)
{
ResultsTextBox.Text += "\r\nDownloads failed.";
}
// ***Enable the Start button in case you want to run the program again.
finally
{
StartButton.IsEnabled = true;
}
}
変更の結果、ボタンは AccessTheWebAsync、Web サイトをダウンロードしながら、この処理は入力し直すことはできません応答しません。
操作をキャンセル、再起動します。
[開始] のボタンを無効にする代わりに、ボタンをアクティブとして保持できますが、ユーザーがボタンをもう一度クリックすると、既に開始された操作が実行、次のように最新する操作をキャンセルします。
キャンセル処理の詳細については、単一のアプリケーションの微調整を参照してください。
このシナリオを設定するには、App 例を確認し、実行します。に用意されている基本コードに対して次の変更を行います。終了するアプリケーションを単一の例: .NET のデスクトップ アプリケーションの再入 または 単一の例: Windows ストアの再入 Apps からダウンロードできます。このプロジェクトの名前は CancelAndRestart です。
すべてのメソッドのスコープ内にある CancellationTokenSource の変数、ctsを宣言します。
Class MainWindow // Or Class MainPage ' *** Declare a System.Threading.CancellationTokenSource. Dim cts As CancellationTokenSource
public partial class MainWindow : Window // Or class MainPage { // *** Declare a System.Threading.CancellationTokenSource. CancellationTokenSource cts;
StartButton_Clickでは、操作が既に行われているかどうかを確認します。cts の値が null (Visual Basic のNothing) の場合、操作が既にアクティブになりません。値が null 以外の場合、既に実行されている操作はキャンセル。
' *** If a download process is already underway, cancel it. If cts IsNot Nothing Then cts.Cancel() End If
// *** If a download process is already underway, cancel it. if (cts != null) { cts.Cancel(); }
現在のプロセスを表す別の値に cts を設定します。
' *** Now set cts to cancel the current process if the button is chosen again. Dim newCTS As CancellationTokenSource = New CancellationTokenSource() cts = newCTS
// *** Now set cts to a new value that you can use to cancel the current process // if the button is chosen again. CancellationTokenSource newCTS = new CancellationTokenSource(); cts = newCTS;
StartButton_Clickの最後に、現在のプロセスは、完全なので、null に cts の値を設定します。
' *** When the process completes, signal that another process can proceed. If cts Is newCTS Then cts = Nothing End If
// *** When the process is complete, signal that another process can begin. if (cts == newCTS) cts = null;
次のコードは 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
private async void StartButton_Click(object sender, RoutedEventArgs e)
{
// This line is commented out to make the results clearer in the output.
//ResultsTextBox.Clear();
// *** If a download process is already underway, cancel it.
if (cts != null)
{
cts.Cancel();
}
// *** Now set cts to cancel the current process if the button is chosen again.
CancellationTokenSource newCTS = new CancellationTokenSource();
cts = newCTS;
try
{
// ***Send cts.Token to carry the message if there is a cancellation request.
await AccessTheWebAsync(cts.Token);
}
// *** Catch cancellations separately.
catch (OperationCanceledException)
{
ResultsTextBox.Text += "\r\nDownloads canceled.\r\n";
}
catch (Exception)
{
ResultsTextBox.Text += "\r\nDownloads failed.\r\n";
}
// *** When the process is complete, signal that another process can proceed.
if (cts == newCTS)
cts = null;
}
AccessTheWebAsyncで、次の変更を行います。
StartButton_Clickからのキャンセル トークンを受け取るためのパラメーターを追加します。
GetAsync が CancellationToken の引数を受け取るため、サイトをダウンロードするには GetAsync のメソッドを使用します。
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
// *** Provide a parameter for the CancellationToken from StartButton_Click.
async Task AccessTheWebAsync(CancellationToken ct)
{
// Declare an HttpClient object.
HttpClient client = new HttpClient();
// Make a list of web addresses.
List<string> urlList = SetUpURLList();
var total = 0;
var position = 0;
foreach (var url in urlList)
{
// *** Use the HttpClient.GetAsync method because it accepts a
// cancellation token.
HttpResponseMessage response = await client.GetAsync(url, ct);
// *** Retrieve the website contents from the HttpResponseMessage.
byte[] urlContents = await response.Content.ReadAsByteArrayAsync();
// *** Check for cancellations before displaying information about the
// latest site.
ct.ThrowIfCancellationRequested();
DisplayResults(url, urlContents, ++position);
// Update the total.
total += urlContents.Length;
}
// Display the total count for all of the websites.
ResultsTextBox.Text +=
string.Format("\r\n\r\nTOTAL bytes returned: {0}\r\n", total);
}
このアプリケーションの実行中に複数回 [開始] のボタンを選択すると、次の出力に似ている結果を生成する必要があります。
1. msdn.microsoft.com/en-us/library/hh191443.aspx 83732
2. msdn.microsoft.com/en-us/library/aa578028.aspx 205273
3. msdn.microsoft.com/en-us/library/jj155761.aspx 29019
4. msdn.microsoft.com/en-us/library/hh290140.aspx 122505
5. msdn.microsoft.com/en-us/library/hh524395.aspx 68959
6. msdn.microsoft.com/en-us/library/ms404677.aspx 197325
Download canceled.
1. msdn.microsoft.com/en-us/library/hh191443.aspx 83732
2. msdn.microsoft.com/en-us/library/aa578028.aspx 205273
3. msdn.microsoft.com/en-us/library/jj155761.aspx 29019
Download canceled.
1. msdn.microsoft.com/en-us/library/hh191443.aspx 83732
2. msdn.microsoft.com/en-us/library/aa578028.aspx 205273
3. msdn.microsoft.com/en-us/library/jj155761.aspx 29019
4. msdn.microsoft.com/en-us/library/hh290140.aspx 117152
5. msdn.microsoft.com/en-us/library/hh524395.aspx 68959
6. msdn.microsoft.com/en-us/library/ms404677.aspx 197325
7. msdn.microsoft.com 42972
8. msdn.microsoft.com/en-us/library/ff730837.aspx 146159
TOTAL bytes returned: 890591
ユーザーが操作を再起動するたびに部分をリスト ボックスをクリアするにはなくすため、コメント StartButton_Click の最初のコード行。
複数の操作を実行して出力をキューに配置します。
この 3 番目の例では、ユーザーが [開始] のボタンを選択すると、完了まで実行されたすべての操作を開始するたびアプリケーションが別の非同期操作する最も複雑です。すべての要求された操作はリストから Web サイトを非同期にダウンロードしますが、操作からの出力は順次表示されます。つまり、実際のダウンロードのアクティビティは 再入の確認 の出力を示していますが、各グループの結果リストは別についてため、インターリーブされます。
操作は、グローバル Task、pendingWorkを共有します、プロセスのゲートキーパーとして機能する。
コードに貼り付けることによってこの例を アプリケーションをビルドの変更を実行できますが、サンプルをダウンロードし、QueueResults でプロジェクトを実行または アプリケーションのダウンロード の手順を実行できます。
次の出力は、ユーザーが一度だけ [開始] のボタンを選択した場合の結果を示します。結果が最初に [開始] のボタンで選択されていることを、文字のラベルは、示します。ダウンロードの数はターゲットの一覧で URL の順序を示します。
#Starting group A.
#Task assigned for group A.
A-1. msdn.microsoft.com/en-us/library/hh191443.aspx 87389
A-2. msdn.microsoft.com/en-us/library/aa578028.aspx 209858
A-3. msdn.microsoft.com/en-us/library/jj155761.aspx 30870
A-4. msdn.microsoft.com/en-us/library/hh290140.aspx 119027
A-5. msdn.microsoft.com/en-us/library/hh524395.aspx 71260
A-6. msdn.microsoft.com/en-us/library/ms404677.aspx 199186
A-7. msdn.microsoft.com 53266
A-8. msdn.microsoft.com/en-us/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/en-us/library/hh191443.aspx 87389
A-2. msdn.microsoft.com/en-us/library/aa578028.aspx 207089
A-3. msdn.microsoft.com/en-us/library/jj155761.aspx 30870
A-4. msdn.microsoft.com/en-us/library/hh290140.aspx 119027
A-5. msdn.microsoft.com/en-us/library/hh524395.aspx 71259
A-6. msdn.microsoft.com/en-us/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/en-us/library/ff730837.aspx 148010
TOTAL bytes returned: 916095
B-1. msdn.microsoft.com/en-us/library/hh191443.aspx 87389
B-2. msdn.microsoft.com/en-us/library/aa578028.aspx 207089
B-3. msdn.microsoft.com/en-us/library/jj155761.aspx 30870
B-4. msdn.microsoft.com/en-us/library/hh290140.aspx 119027
B-5. msdn.microsoft.com/en-us/library/hh524395.aspx 71260
B-6. msdn.microsoft.com/en-us/library/ms404677.aspx 199186
#Group A is complete.
B-7. msdn.microsoft.com 53266
B-8. msdn.microsoft.com/en-us/library/ff730837.aspx 148010
TOTAL bytes returned: 916097
C-1. msdn.microsoft.com/en-us/library/hh191443.aspx 87389
C-2. msdn.microsoft.com/en-us/library/aa578028.aspx 207089
#Group B is complete.
C-3. msdn.microsoft.com/en-us/library/jj155761.aspx 30870
C-4. msdn.microsoft.com/en-us/library/hh290140.aspx 119027
C-5. msdn.microsoft.com/en-us/library/hh524395.aspx 72765
C-6. msdn.microsoft.com/en-us/library/ms404677.aspx 199186
C-7. msdn.microsoft.com 56190
C-8. msdn.microsoft.com/en-us/library/ff730837.aspx 148010
TOTAL bytes returned: 920526
#Group C is complete.
グループ A が終了する前に各グループのグループの B、および C の開始、出力を別に表示されます。次に、グループ A のすべての出力は、グループの B のすべての出力、およびグループ化の C のすべての出力に続けて先頭に表示されます。アプリケーションでは、URL に URL の一覧に表示される順序でグループを常に表示、各グループに、順序で個々の Web サイトに関する情報を表示します。
ただし、ダウンロードが実際に出現する順序を予測することはできません。複数のグループが開始されると、生成するダウンロードのタスクはすべてのアクティブ状態。A-1 が B-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)
public partial class MainWindow : Window // Class MainPage in Windows Store app.
{
// ***Declare the following variables where all methods can access them.
private Task pendingWork = null;
private char group = (char)('A' - 1);
Task の変数、pendingWorkは、プロセスを無人し、グループは別のグループの表示の操作を中断することを防止できます。文字の変数、groupは、結果が期待された順序で表示されることを確認するために、異なるグループからの出力をラベル。
クリック イベント ハンドラー
ユーザーが [開始] のボタンをクリックするたびに 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
private async void StartButton_Click(object sender, RoutedEventArgs e)
{
// ***Verify that each group's results are displayed together, and that
// the groups display in order, by marking each group with a letter.
group = (char)(group + 1);
ResultsTextBox.Text += string.Format("\r\n\r\n#Starting group {0}.", group);
try
{
// *** Pass the group value to AccessTheWebAsync.
char finishedGroup = await AccessTheWebAsync(group);
// The following line verifies a successful return from the download and
// display procedures.
ResultsTextBox.Text += string.Format("\r\n\r\n#Group {0} is complete.\r\n", finishedGroup);
}
catch (Exception)
{
ResultsTextBox.Text += "\r\nDownloads failed.";
}
}
AccessTheWebAsync のメソッド
この例では、2 とおりの方法に AccessTheWebAsync を分割します。最初のメソッド、AccessTheWebAsyncは、グループのすべてのダウンロードのタスクを起動し、表示のプロセスを制御するには pendingWork を設定します。メソッドは、統合言語クエリ (LINQ クエリ) を使用して、すべてのダウンロードを開始する ToArray<TSource> が同時に委ねます。
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
private async Task<char> AccessTheWebAsync(char grp)
{
HttpClient client = new HttpClient();
// Make a list of the web addresses to download.
List<string> urlList = SetUpURLList();
// ***Kick off the downloads. The application of ToArray activates all the download tasks.
Task<byte[]>[] getContentTasks = urlList.Select(url => client.GetByteArrayAsync(url)).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("\r\n#Task assigned for group {0}. Download tasks are active.\r\n", 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;
}
FinishOneGroupAsync のメソッド
このメソッドは、グループのダウンロードのタスクをようにし、それぞれを待機し、ダウンロードされたサイトの長さを表示、および長さの合計に追加します。
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
private async Task FinishOneGroupAsync(List<string> urls, Task<byte[]>[] contentTasks, char grp)
{
// ***Wait for the previous group to finish displaying results.
if (pendingWork != null) await pendingWork;
int total = 0;
// contentTasks is the array of Tasks that was created in AccessTheWebAsync.
for (int i = 0; i < contentTasks.Length; i++)
{
// Await the download of a particular URL, and then display the URL and
// its length.
byte[] content = await contentTasks[i];
DisplayResults(urls[i], content, i, grp);
total += content.Length;
}
// Display the total count for all of the websites.
ResultsTextBox.Text +=
string.Format("\r\n\r\nTOTAL bytes returned: {0}\r\n", total);
}
コードに貼り付けることによってこの例を アプリケーションをビルドの変更を実行できますが、サンプルをダウンロードし、QueueResults でプロジェクトを実行または アプリケーションのダウンロード の手順を実行できます。
目的のポイント
出力のシャープ記号 (#) を起動する情報の行は、この例の動作を明確にします。
出力は、次のパターンを示しています。
グループは、前のグループが出力を表示する間は、前のグループの出力の表示が中断されない呼び出すことができます。
#Starting group A. #Task assigned for group A. Download tasks are active. A-1. msdn.microsoft.com/en-us/library/hh191443.aspx 87389 A-2. msdn.microsoft.com/en-us/library/aa578028.aspx 207089 A-3. msdn.microsoft.com/en-us/library/jj155761.aspx 30870 A-4. msdn.microsoft.com/en-us/library/hh290140.aspx 119037 A-5. msdn.microsoft.com/en-us/library/hh524395.aspx 71260 #Starting group B. #Task assigned for group B. Download tasks are active. A-6. msdn.microsoft.com/en-us/library/ms404677.aspx 199186 A-7. msdn.microsoft.com 53078 A-8. msdn.microsoft.com/en-us/library/ff730837.aspx 148010 TOTAL bytes returned: 915919 B-1. msdn.microsoft.com/en-us/library/hh191443.aspx 87388 B-2. msdn.microsoft.com/en-us/library/aa578028.aspx 207089 B-3. msdn.microsoft.com/en-us/library/jj155761.aspx 30870 #Group A is complete. B-4. msdn.microsoft.com/en-us/library/hh290140.aspx 119027 B-5. msdn.microsoft.com/en-us/library/hh524395.aspx 71260 B-6. msdn.microsoft.com/en-us/library/ms404677.aspx 199186 B-7. msdn.microsoft.com 53078 B-8. msdn.microsoft.com/en-us/library/ff730837.aspx 148010 TOTAL bytes returned: 915908
pendingWork のタスクは、最初にを起動したグループはでのみ FinishOneGroupAsync の先頭に null (Visual Basic のNothing) です。FinishOneGroupAsyncに達すると A がありません。まだ完了した要求の式をグループ化します。したがって、コントロールは AccessTheWebAsyncに戻らず、pendingWork への最初の割り当てが発生します。
次の 2 種類の行が出力に常に同時に表示されます。コード グループは StartButton_Click の操作を開始することと pendingWorkにグループのタスクを再配置の間では中断されません。
#Starting group B. #Task assigned for group B. Download tasks are active.
グループが StartButton_Clickに入った後、操作は、操作が FinishOneGroupAsyncになるまで、式を終了しません。したがって、他の操作は、コード内のそのセグメントの間にコントロールを派生させることはできません。
App 例を確認し、実行します。
サンプル アプリケーションをより深く理解するために、をダウンロードするか、独自ビルド、このトピックの最後にアプリケーションを実行せずにコードを確認できます。
[!メモ]
Windows Presentation Foundation (WPF) のデスクトップ アプリケーションとして例を実行するには、Visual Studio 2012 Visual Studio には、Windows のデスクトップの 2012 を表します。、またはのコンピューターに .NET Framework 4.5 がインストールされている必要があります。
Windows ストア アプリケーションとして例を実行するには、コンピューターにインストールされている Windows 8 が必要です。また、Visual Studio で例を実行する場合、Visual Studio 2012 が Visual Studio には、Windows 8 の 2012 を表します。 あるインストールします。Visual Studio 2010 では、.NET Framework 4.5 を対象とするプロジェクトを読み込むことができません。
アプリケーションのダウンロード
圧縮ファイルをから 単一の例: .NET のデスクトップ アプリケーションの再入 または 単一の例: Windows ストアの再入 Appsダウンロードします。
ダウンロードした配置し、Visual Studio を起動します。ファイルを表します。
メニュー バーで [ファイル]、[開く]、[プロジェクト/ソリューション] の順に選択します。
配置されたサンプル コードを保持する移動し、ソリューション (.sln) ファイルにフォルダーを開きます。
[ソリューション エクスプローラー] では、実行する開き、[Set as StartUpProject] を選択します。プロジェクトのショートカット メニューが。
プロジェクトをビルドして実行するには、Ctrl キーを選択します。
アプリケーションをビルド
次のセクションでは、WPF アプリケーションまたは Windows ストア アプリケーションとして例をビルドするコードを示します。
WPF アプリケーションをビルドするには
Visual Studio 2012 を起動します。
メニュー バーで [ファイル]、[新規]、[プロジェクト] の順にクリックします。
[新しいプロジェクト] ダイアログ ボックスが表示されます。
[インストールされたテンプレート] のペインで、[Visual Basic] か [Visual C#] を展開し、[ウィンドウ] を展開します。
プロジェクトの種類の一覧で、[WPF アプリケーション] を選択します。
プロジェクト WebsiteDownloadWPFの名前を指定し、を [OK] のボタンをクリックします。
ソリューション エクスプローラーに新しいプロジェクトが表示されます。
Visual Studio では、エディターを選択します [MainWindow.xaml] のタブを参照してください。
タブが表示されない場合は、[ソリューション エクスプローラー] で MainWindow.xaml のショートカット メニューを開き、[コードの表示] を選択します。
MainWindow.xaml の [XAML] ビューで、次のコードに置き換えます。
<Window x:Class="MainWindow" xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:WebsiteDownloadWPF" xmlns:d="https://schemas.microsoft.com/expression/blend/2008" xmlns:mc="https://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>
<Window x:Class="WebsiteDownloadWPF.MainWindow" xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:WebsiteDownloadWPF" xmlns:d="https://schemas.microsoft.com/expression/blend/2008" xmlns:mc="https://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.cs のショートカット メニューを開き、[コードの表示] を選択します。
MainWindow.xaml.vb または MainWindow.xaml.cs で、次のコードに置き換えます。
' 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) ' 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/en-us/library/hh191443.aspx", "https://msdn.microsoft.com/en-us/library/aa578028.aspx", "https://msdn.microsoft.com/en-us/library/jj155761.aspx", "https://msdn.microsoft.com/en-us/library/hh290140.aspx", "https://msdn.microsoft.com/en-us/library/hh524395.aspx", "https://msdn.microsoft.com/en-us/library/ms404677.aspx", "https://msdn.microsoft.com", "https://msdn.microsoft.com/en-us/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("http://", "") ' 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
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; // Add the following using directives, and add a reference for System.Net.Http. using System.Net.Http; using System.Threading; namespace WebsiteDownloadWPF { public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } private async void StartButton_Click(object sender, RoutedEventArgs e) { // This line is commented out to make the results clearer in the output. //ResultsTextBox.Text = ""; try { await AccessTheWebAsync(); } catch (Exception) { ResultsTextBox.Text += "\r\nDownloads failed."; } } private async Task AccessTheWebAsync() { // Declare an HttpClient object. HttpClient client = new HttpClient(); // Make a list of web addresses. List<string> urlList = SetUpURLList(); var total = 0; var position = 0; foreach (var url in urlList) { // GetByteArrayAsync returns a task. At completion, the task // produces a byte array. byte[] urlContents = await client.GetByteArrayAsync(url); DisplayResults(url, urlContents, ++position); // Update the total. total += urlContents.Length; } // Display the total count for all of the websites. ResultsTextBox.Text += string.Format("\r\n\r\nTOTAL bytes returned: {0}\r\n", total); } private List<string> SetUpURLList() { List<string> urls = new List<string> { "https://msdn.microsoft.com/en-us/library/hh191443.aspx", "https://msdn.microsoft.com/en-us/library/aa578028.aspx", "https://msdn.microsoft.com/en-us/library/jj155761.aspx", "https://msdn.microsoft.com/en-us/library/hh290140.aspx", "https://msdn.microsoft.com/en-us/library/hh524395.aspx", "https://msdn.microsoft.com/en-us/library/ms404677.aspx", "https://msdn.microsoft.com", "https://msdn.microsoft.com/en-us/library/ff730837.aspx" }; return urls; } private void DisplayResults(string url, byte[] content, int pos) { // 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://". var displayURL = url.Replace("http://", ""); // Display position in the URL list, the URL, and the number of bytes. ResultsTextBox.Text += string.Format("\n{0}. {1,-58} {2,8}", pos, displayURL, content.Length); } } }
プログラムを実行するには、Ctrl キーを選択し、数回 [開始] のボタンをクリックします。
再入を処理する 起動ボタンを無効にします。、操作をキャンセル、再起動します。、または 複数の操作を実行して出力をキューに配置します。 の変更を行います。
Windows ストア アプリケーションをビルドするには
Visual Studio 2012 を起動します。
メニュー バーで [ファイル]、[新規]、[プロジェクト] の順にクリックします。
[新しいプロジェクト] ダイアログ ボックスが表示されます。
[インストール済み] では、[テンプレート] のカテゴリは、[Visual Basic] か [Visual C#] を展開し、[Windows ストア] を展開します。
プロジェクトの種類の一覧で、[Blue / Z] を選択します。
プロジェクト WebsiteDownloadWinの名前を指定し、を [OK] のボタンをクリックします。
ソリューション エクスプローラーに新しいプロジェクトが表示されます。
[ソリューション エクスプローラー] では、MainPage.xaml のショートカット メニューを開き、[開く] を選択します。
MainPage.xaml の [XAML] のペインで、次のコードに置き換えます。
<Page x:Class="WebsiteDownloadWin.MainPage" xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:WebsiteDownloadWin" xmlns:d="https://schemas.microsoft.com/expression/blend/2008" xmlns:mc="https://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" FontSize="12"> <Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}"> <Button x:Name="StartButton" Content="Start" HorizontalAlignment="Left" Margin="325,77,0,0" VerticalAlignment="Top" Click="StartButton_Click" Height="145" Background="#FFA89B9B" FontSize="36" Width="711" /> <TextBox x:Name="ResultsTextBox" HorizontalAlignment="Left" Margin="325,222,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Height="546" FontSize="10" ScrollViewer.VerticalScrollBarVisibility="Visible" Width="711" FontFamily="Lucida Console" /> </Grid> </Page>
テキスト ボックスと [開始] ボタンを含む簡単なウィンドウは、MainPage.xaml の [デザイン] のペインに表示されます。
[ソリューション エクスプローラー] では、MainPage.xaml.cs のショートカット メニューを開き、[コードの表示] を選択します。
次のコードで MainPage.xaml.cs のコードに置き換えます。
' Add the following Imports statements. Imports System.Threading.Tasks Imports System.Threading Imports System.Net.Http Public NotInheritable Class MainPage Inherits Page Protected Overrides Sub OnNavigatedTo(e As Navigation.NavigationEventArgs) End Sub 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 = "" 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/en-us/library/hh191443.aspx", "https://msdn.microsoft.com/en-us/library/aa578028.aspx", "https://msdn.microsoft.com/en-us/library/jj155761.aspx", "https://msdn.microsoft.com/en-us/library/hh290140.aspx", "https://msdn.microsoft.com/en-us/library/hh524395.aspx", "https://msdn.microsoft.com/en-us/library/ms404677.aspx", "https://msdn.microsoft.com", "https://msdn.microsoft.com/en-us/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("http://", "") ' 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
using System; using System.Collections.Generic; using System.IO; using System.Linq; using Windows.Foundation; using Windows.Foundation.Collections; using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Controls.Primitives; using Windows.UI.Xaml.Data; using Windows.UI.Xaml.Input; using Windows.UI.Xaml.Media; using Windows.UI.Xaml.Navigation; // Add the following using directives. using System.Threading.Tasks; using System.Threading; using System.Net.Http; namespace WebsiteDownloadWin { public sealed partial class MainPage : Page { public MainPage() { this.InitializeComponent(); } private async void StartButton_Click(object sender, RoutedEventArgs e) { // This line is commented out to make the results clearer in the output. //ResultsTextBox.Text = ""; try { await AccessTheWebAsync(); } catch (Exception) { ResultsTextBox.Text += "\r\nDownloads failed."; } } private async Task AccessTheWebAsync() { // Declare an HttpClient object. HttpClient client = new HttpClient(); // Make a list of web addresses. List<string> urlList = SetUpURLList(); var total = 0; var position = 0; foreach (var url in urlList) { // GetByteArrayAsync returns a task. At completion, the task // produces a byte array. byte[] urlContents = await client.GetByteArrayAsync(url); DisplayResults(url, urlContents, ++position); // Update the total. total += urlContents.Length; } // Display the total count for all of the websites. ResultsTextBox.Text += string.Format("\r\n\r\nTOTAL bytes returned: {0}\r\n", total); } private List<string> SetUpURLList() { List<string> urls = new List<string> { "https://msdn.microsoft.com/en-us/library/hh191443.aspx", "https://msdn.microsoft.com/en-us/library/aa578028.aspx", "https://msdn.microsoft.com/en-us/library/jj155761.aspx", "https://msdn.microsoft.com/en-us/library/hh290140.aspx", "https://msdn.microsoft.com/en-us/library/hh524395.aspx", "https://msdn.microsoft.com/en-us/library/ms404677.aspx", "https://msdn.microsoft.com", "https://msdn.microsoft.com/en-us/library/ff730837.aspx" }; return urls; } private void DisplayResults(string url, byte[] content, int pos) { // 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://". var displayURL = url.Replace("http://", ""); // Display position in the URL list, the URL, and the number of bytes. ResultsTextBox.Text += string.Format("\n{0}. {1,-58} {2,8}", pos, displayURL, content.Length); } } }
プログラムを実行するには、Ctrl キーを選択し、数回 [開始] のボタンをクリックします。
再入を処理する 起動ボタンを無効にします。、操作をキャンセル、再起動します。、または 複数の操作を実行して出力をキューに配置します。 の変更を行います。
参照
処理手順
チュートリアル: Async と Await を使用した Web へのアクセス (C# および Visual Basic)
概念
Async および Await を使用した非同期プログラミング (C# および Visual Basic)