Sdílet prostřednictvím


Podpora vícenásobného přístupu v aplikacích s modifikátorem Async (C# a Visual Basic)

Pokud zahrnete asynchronní kód do vaší aplikace, měli byste vzít v úvahu a případně zabránit vícenásobnému přístupu, který se vztahuje k nutnosti opětovného zadávání asynchronní operace ještě před dokončením.Pokud neidentifikujete a nemanipulujete s možnostmi vícenásobnému přístupu, může způsobit neočekávané výsledky.

V tomto tématu

[!POZNÁMKA]

Pokyny v části Revize a spuštění vzorové aplikace ukazují, jak spustit kód jako aplikaci WPF nebo jako aplikaci Windows Store.

Chcete-li spustit příklad jako aplikaci WPF, musíte mít nainstalovanou aplikaci Visual Studio 2012, Visual Studio 2013, Visual Studio Express 2012 for Windows Desktop, Visual Studio Express 2013 for Windows nebo rozhraní .NET Framework 4.5 nebo 4.5.1 v počítači.

Chcete-li spustit příklad jako aplikaci Windows Store, musíte mít v počítači nainstalován systém Windows 8.Kromě toho pokud chcete spustit příklad ze sady Visual Studio, musíte také mít nainstalováno Visual Studio 2012 Visual Studio 2013, Visual Studio Express 2012 pro Windows Desktop nebo Visual Studio Express 2013 for Windows.

Rozpoznávání vícenásobného přístupu

V příkladu v tomto tématu uživatelé vyberou tlačítko Start pro zahájení asynchronní aplikace, která stáhne řady webů a vypočítá celkový počet bajtů, které byly staženy.Synchronní verze tohoto příkladu odpoví stejným způsobem bez ohledu na to, kolikrát uživatel vybere tlačítko, protože poprvé vlákno uživatelského rozhraní bude tyto události ignorovat až do ukončení aplikace.V asynchronní aplikaci však vlákno UI i nadále odpovídá a můžete znovu zadat asynchronní operaci před dokončením.

Následující příklad zobrazuje očekávaný výstup, pokud uživatel klikne na tlačítko Start pouze jednou.Seznam stažených webových stránek se zobrazuje s velikostí v bajtech pro každý web.Na konci se zobrazuje celkový počet bajtů.

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

Klikne-li však uživatel na tlačítko více než jednou, obslužná rutina události je vyvolána opakovaně, a proces stahování je znovu zadán pokaždé.V důsledku toho je několik asynchronních operací spuštěno současně. Výstup předřadí výsledky a celkový počet bajtů je matoucí.

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

Můžete zkontrolovat kód, který vytváří tento výstup, přechodem na konec tohoto tématu.Můžete experimentovat s kódem stažením řešení do místního počítače a následným spuštěním projektu WebsiteDownload nebo pomocí kódu na konci tohoto tématu k vytvoření vlastního projektu: Další informace a pokyny naleznete v tématu Revize a spuštění vzorové aplikace.

Vyřešení vícenásobného přístupu

Můžete zpracovat vícenásobnost různými způsoby podle toho, co má vaše aplikace provést.Toto téma představuje následující příklady:

Zakázání tlačítka Start

Můžete blokovat tlačítko Start, kdy je spuštěná operace, zakázáním tlačítka v horní části obslužné rutiny události StartButton_Click.Potom můžete znovu povolit tlačítko z bloku finally po ukončení operace tak, aby uživatelé mohli znovu spustit aplikaci.

Následující kód znázorňuje tyto změny, které jsou označeny hvězdičkami.Změny můžete přidat do kódu na konci tohoto tématu nebo si můžete stáhnout hotovou aplikaci z Asynchronní vzorky: Vícenásobnost v desktopových aplikacích .NET nebo Asynchronní vzorky: Vícenásobnost v aplikacích pro Windows Store.Název projektu je 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;
    }
}

V důsledku změny, tlačítko nereaguje zatímco AccessTheWebAsync stahuje webové stránky, takže proces nelze znovu zadat.

Zrušení a opětovné spuštění operace

Namísto zakázání tlačítka Start můžete zachovat tlačítko aktivní, ale pokud uživatel na toto tlačítko znovu klepne, zrušit operaci, která je již spuštěna a nechá pokračovat operaci naposledy spuštěnou.

Další informace o zrušení naleznete v tématu Jemné vyladění asynchronní aplikace.

Pokud chcete nastavit tento scénář, proveďte následující změny základního kódu, který je k dispozici v tématu Revize a spuštění vzorové aplikace.Dokončenou aplikaci můžete také stáhnout z okna Asynchronní příklady: Opětovný vstup do desktopových aplikací .NET Desktop nebo synchronní příklady: Opětovný vstup do aplikací pro Windows Store.Název tohoto projektu je CancelAndRestart.

  1. Deklarujte proměnnou CancellationTokenSource, cts, která je v oboru pro všechny metody.

    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;
    
  2. V StartButton_Click určete, zda operace je již probíhá.Pokud hodnota cts má hodnotu null (Nothing v jazyce Visual Basic), žádná operace ještě není aktivní.Pokud hodnota není null, je zrušena operace, která je již spuštěna.

    ' *** 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();
    }
    
  3. Nastavit cts na jinou hodnotu, která představuje aktuální proces.

    ' *** 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;
    
  4. Na konci StartButton_Click je aktuální proces dokončen, takže nastavte hodnotu cts zpět na hodnotu null.

    ' *** 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;
    

Následující kód ukazuje všechny změny v StartButton_Click.Přidání jsou označena hvězdičkami.

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;
}

Proveďte následující změny v AccessTheWebAsync.

  • Přidat parametr pro přijetí tokenu zrušení z StartButton_Click.

  • Metodu GetAsync použijte ke stažení webových stránek, protože GetAsync přijímá argument CancellationToken.

  • Před voláním DisplayResults pro zobrazení výsledků pro každý stažený web, zkontrolujte ct k ověření, že aktuální operace nebyla zrušena.

Následující kód znázorňuje tyto změny, které jsou označeny hvězdičkami.

' *** 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);
}   

Zvolíte-li tlačítko Start několikrát během spuštění této aplikace, mohou být vráceny výsledky, které se podobají následujícímu výstupu.

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

Chcete-li odstranit dílčí seznamy, zrušte komentář u prvního řádku kódu v StartButton_Click pro vymazání textového pole pokaždé, když uživatel znovu spustí operaci.

Spuštění více operací a zařazení výstupu do fronty

Tento třetí příklad je v nejkomplikovanější v tomu, že aplikace spustí jinou asynchronní operaci pokaždé, když uživatel vybere tlačítko Start a všechny operace běží až do ukončení.Všechny požadované operace stahují webové stránky ze seznamu asynchronně, ale výstup z operací je uveden postupně.To znamená, že skutečná aktivita stahování je prokládána, jak poukazuje výstup Rozpoznávání vícenásobného přístupu, ale seznam výsledků pro každou skupinu je předkládán samostatně.

Operace sdílí globální Task, pendingWork, který slouží jako správce pro zpracování zobrazení.

Tento příklad lze spustit zadáním nebo vložením změn do kódu v článku Sestavení aplikace nebo můžete postupovat podle pokynů v tématu Stažení aplikace ke stažení vzorku a spuštění projektu QueueResults.

Následující výstup zobrazuje výsledek toho, když uživatel klikne na tlačítko Start pouze jednou.Označení písmenem A označuje, že výsledek pochází z prvního stisku tlačítka Start.Čísla popisují pořadí adres URL v seznamu cílů ke stažení.

#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.

Pokud uživatel klikne na tlačítko Start třikrát, aplikace vytvoří výstup, který se podobá následujícím řádkům.Informační řádky, které začínají znakem křížku (#), sledují průběh aplikace.

#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.

Skupiny B a C se spustí před dokončením skupiny A, ale výstup pro jednotlivé skupiny se zobrazí odděleně.Nejprve se zobrazí výstup pro skupinu A, následovaný všemi výstupy pro skupinu B a pak veškerý výstup pro skupinu C.Aplikace vždy zobrazí skupiny v pořadí a pro každou skupinu vždy zobrazí informace o jednotlivých webech v pořadí, ve kterém se adresy URL nachází v seznamu adres URL.

Nelze však předvídat pořadí, ve kterých ke stažení skutečně došlo.Po spuštění více skupin budou aktivní všechny úlohy stahování, které generují.Nelze předpokládat, že A-1 se stáhne před B-1 a nelze předpokládat, že A-1 se stáhne před A-2.

Globální definice

Ukázka kódu obsahuje následující dvě globální deklarace, které jsou viditelné ze všech metod.

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);

Proměnná Task, pendingWork, dohlíží na proces zobrazení a zabrání jakékoli skupině v přerušení operace zobrazení jiné skupiny.Proměnné znaku group, značí výstup z různých skupin, pokud chcete ověřit, že se výsledky zobrazí v očekávaném pořadí.

Obslužná rutina události kliknutí

Obslužná rutina události StartButton_Click zvyšuje písmeno skupiny pokaždé, když uživatel klikne na tlačítko Start.Potom rutina volá AccessTheWebAsync ke spuštění operace stahování.

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.";
    }
}

Metoda AccessTheWebAsync

V tomto příkladu se rozdělí AccessTheWebAsync do dvou metod.První metoda AccessTheWebAsync spustí všechny úlohy stahování pro skupinu a nastaví pendingWork pro řízení procesu zobrazení.Metoda se používá dotaz LINQ a ToArray``1 pro zahájení současného stahování všech úloh.

AccessTheWebAsync pak zavolá FinishOneGroupAsync pro čekání na dokončení každého stažení a zobrazení jeho délky.

FinishOneGroupAsync vrátí úkol, který je přiřazen k pendingWork v AccessTheWebAsync.Tato hodnota zabraňuje přerušení jinou operací před dokončením úkolu.

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;
}

Metoda FinishOneGroupAsync

Tato metoda projde stažené úlohy ve skupině a čeká na jednotlivé z nich při současném zobrazení délky staženého webu a přičtením délky k celku.

První příkaz v FinishOneGroupAsync používá pendingWork k tomu, aby se ujistil, že zadávání metody není v konfliktu s operací, která je již v procesu zobrazení, nebo která již čeká.Pokud tato operace probíhá, operace zadávání musí čekat, než přijde na řadu.

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);
}

Tento příklad lze spustit zadáním nebo vložením změn do kódu v článku Sestavení aplikace nebo můžete postupovat podle pokynů v tématu Stažení aplikace ke stažení vzorku a spuštění projektu QueueResults.

Body zájmu

Informační řádky, které začínají znakem křížku (#) ve výstupu značí, jak tento příklad funguje.

Výstup zobrazuje následující vzory.

  • Skupina může být spuštěna, když předchozí skupina zobrazuje výstup, ale zobrazení výstupu předchozí skupiny není přerušeno.

    #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
    
  • Úkol pendingWork má hodnotu null (Nothing v jazyce Visual Basic) na začátku FinishOneGroupAsync pouze u skupiny A, která začíná jako první.Skupina A dosud nedokončila výraz await, když dosáhl FinishOneGroupAsync.Proto se ovládací prvek nevrátil do AccessTheWebAsync a první přiřazení k pendingWork se neuskutečnilo.

  • Následující dva řádky se ve výstupu vždy zobrazí společně.Kód není nikdy přerušen mezi spuštěním operace skupiny StartButton_Click a přiřazením úkolu skupiny pro pendingWork.

    #Starting group B.
    #Task assigned for group B. Download tasks are active.
    

    Po vstupu skupiny do StartButton_Click, operace nedokončí výraz await, dokud operace nevstoupí do FinishOneGroupAsync.Proto žádná další operace nemůže získat kontrolu během tohoto segmentu kódu.

Prostudování a spuštění ukázkové aplikace

Pro lepší pochopení příkladu aplikace si ho můžete stáhnout, sestavit sami nebo zkontrolovat kód na konci tohoto tématu bez implementace aplikace.

[!POZNÁMKA]

Chcete-li spustit příklad jako aplikaci pro stolní počítače Windows Presentation Foundation (WPF), musíte mít nainstalovanou aplikaci Visual Studio 2012, Visual Studio 2013, Visual Studio Express 2012 for Windows Desktop, Visual Studio Express 2013 for Windows nebo rozhraní .NET Framework 4.5 nebo 4.5.1 v počítači.

Chcete-li spustit příklad jako aplikaci Windows Store, musíte mít v počítači nainstalován systém Windows 8.Kromě toho, pokud chcete spustit příklad ze sady Visual Studio, musíte také mít nainstalováno Visual Studio 2012 Visual Studio 2013, Visual Studio Express 2012 pro Windows 8 nebo Visual Studio Express 2013 for Windows.Projekty sady Visual Studio 2010 nemohou načítat projekty určené pro rozhraní .NET Framework 4.5.

Stažení aplikace

  1. Stažení komprimovaného souboru z Asynchronní vzorky: vícenásobný přístup v aplikacích .NET pro počítač nebo Asynchronní vzorky: vícenásobný přístup v aplikacích Windows Store.

  2. Dekomprimujte soubor, který jste stáhli a poté spusťte Visual Studio.

  3. Na panelu nabídky vyberte možnosti Soubor, Otevřít, Projekt/řešení.

  4. Přejděte do složky obsahující dekomprimovaný ukázkový kód a poté otevřete soubor řešení (.sln).

  5. Průzkumníku řešení otevřete místní nabídku projektu, který chcete spustit, a poté vyberte položku Nastavit jako výchozí projekt.

  6. Výběrem tlačítek CTRL+F5 sestavte a spusťte projekt.

Vytvoření aplikace

Následující části obsahují kód k vytvoření příkladu jako aplikace WPF nebo aplikace Windows Store.

Vytvoření aplikace WPF

  1. Spusťte aplikaci Visual Studio.

  2. Na panelu nabídky vyberte možnosti Soubor, Nový, Projekt.

    Otevře se dialogové okno Nový projekt.

  3. V podokně Nainstalované šablony rozbalte možnost Visual Basic nebo Visual C# a potom rozbalte možnost Windows.

  4. V seznamu typy projektů, klepněte na příkaz Aplikace WPF.

  5. Pojmenujte projekt WebsiteDownloadWPF a stiskněte tlačítko OK.

    V podokně Průzkumník řešení se zobrazí nový projekt.

  6. V editoru kódu sady Visual Studio zvolte kartu MainWindow.xaml.

    Pokud karta není zobrazena, otevřete místní nabídku souboru MainWindow.xaml v Průzkumníkovi řešení a vyberte možnost Zobrazit kód.

  7. V zobrazení XAML pro souboru MainWindow.xaml nahraďte kód následujícím kódem.

    <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>
    

    Jednoduché okno obsahující textové pole a tlačítko se zobrazí v zobrazení Návrh souboru MainWindow.xaml.

  8. Přidejte odkaz pro System.Net.Http.

  9. V Průzkumníku řešení otevřete místní nabídku pro soubor MainWindow.xaml.vb nebo MainWindow.xaml.cs a pak zvolte možnost Zobrazit kód.

  10. Nahraďte kód v souborech MainWindow.xaml.vb nebo MainWindow.xaml.cs za následující kód.

    ' 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);
            }
        }
    }
    
  11. Zvolte klávesy CTRL+ F5 ke spuštění programu a pak několikrát vyberte tlačítko Start.

  12. Proveďte požadované změny z nabídky Zakázat tlačítko Start, Zrušit a znovu spustit operaci nebo Spustit více operací a vložit výstup do fronty pro zpracování vícenásobného přístupu.

Vytvoření aplikace pro Windows Store

  1. Spusťte aplikaci Visual Studio.

  2. Na panelu nabídky vyberte možnosti Soubor, Nový, Projekt.

    Otevře se dialogové okno Nový projekt.

  3. V kategorii Nainstalováno, Šablony rozbalte možnost Visual Basic nebo Visual C# a pak rozbalte možnost Windows Store.

  4. V seznamu typy projektů, klepněte na příkaz Prázdná aplikace (XAML).

  5. Pojmenujte projekt WebsiteDownloadWin a stiskněte tlačítko OK.

    V podokně Průzkumník řešení se zobrazí nový projekt.

  6. V Průzkumníku řešení otevřete místní nabídku pro MainPage.xaml a pak zvolte Otevřít.

  7. V okně XAML pro soubor MainPage.xaml nahraďte kód následujícím kódem.

    <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>
    

    Jednoduché okno obsahující textové pole a tlačítko Start se zobrazí v okně Návrh souboru MainPage.xaml.

  8. V Průzkumníku řešení otevřete místní nabídku pro soubor MainPage.xaml nebo MainPage.xaml.cs a pak zvolte možnost Zobrazit kód.

  9. Nahraďte kód pro MainPage.xaml.vb nebo MainPage.xaml.cs za následující kód.

    ' 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);
            }
        }
    }
    
  10. Zvolte klávesy CTRL+ F5 ke spuštění programu a pak několikrát vyberte tlačítko Start.

  11. Proveďte požadované změny z nabídky Zakázat tlačítko Start, Zrušit a znovu spustit operaci nebo Spustit více operací a vložit výstup do fronty pro zpracování vícenásobného přístupu.

Viz také

Úkoly

Návod: Přístup k webu pomocí modifikátoru Async a operátoru Await (C# a Visual Basic)

Koncepty

Asynchronní programování pomocí modifikátoru Async a operátoru Await (C# a Visual Basic)

Další zdroje

Asynchronní programování (aplikace pro Windows Store)

Rychlý začátek: volání asynchronních rozhraní API v jazyce C# nebo Visual Basic