Bagikan melalui


Pemrograman asinkron dengan Async dan Await (Visual Basic)

Anda dapat menghindari penyempitan performa dan meningkatkan respons keseluruhan aplikasi Anda dengan menggunakan pemrograman asinkron. Namun, teknik tradisional untuk menulis aplikasi asinkron bisa rumit, membuatnya sulit ditulis, di-debug, dan dipertahankan.

Visual Studio 2012 memperkenalkan pendekatan yang disederhanakan, pemrograman asinkron, yang memanfaatkan dukungan asinkron dalam .NET Framework 4.5 dan yang lebih tinggi serta di Windows Runtime. Pengompilasi melakukan pekerjaan sulit yang biasa dilakukan pengembang, dan aplikasi Anda mempertahankan struktur logis yang menyerupai kode sinkron. Akibatnya, Anda mendapatkan semua keuntungan dari pemrograman asinkron dengan sebagian kecil dari upaya.

Topik ini memberikan gambaran umum tentang kapan dan bagaimana menggunakan pemrograman asinkron dan menyertakan tautan ke topik dukungan yang berisi detail dan contoh.

Asinkron meningkatkan responsivitas

Asinkron sangat penting untuk aktivitas yang berpotensi memblokir, seperti ketika aplikasi Anda mengakses web. Akses ke sumber daya web terkadang lambat atau tertunda. Jika aktivitas seperti itu diblokir dalam proses sinkron, seluruh aplikasi harus menunggu. Dalam proses asinkron, aplikasi dapat dilanjutkan dengan pekerjaan lain yang tidak bergantung pada sumber daya web sampai tugas yang berpotensi memblokir selesai.

Tabel berikut menunjukkan area umum di mana pemrograman asinkron meningkatkan responsivitas. API yang tercantum dari .NET Framework 4.5 dan Windows Runtime berisi metode yang mendukung pemrograman asinkron.

Area aplikasi API pendukung yang berisi metode asinkron
Akses web HttpClient, SyndicationClient
Bekerja dengan berkas StorageFile,StreamWriter,StreamReader,XmlReader
Bekerja dengan gambar MediaCapture, , BitmapEncoderBitmapDecoder
Pemrograman WCF Operasi Sinkron dan Asinkron

Asinkron terbukti sangat berharga bagi aplikasi yang mengakses utas UI karena semua aktivitas terkait UI biasanya berbagi satu utas. Jika ada proses yang diblokir dalam aplikasi sinkron, semua diblokir. Aplikasi Anda berhenti merespons, dan Anda mungkin menyimpulkan bahwa aplikasi tersebut gagal, padahal sebenarnya hanya sedang menunggu.

Saat Anda menggunakan metode asinkron, aplikasi terus merespons UI. Anda dapat mengubah ukuran atau meminimalkan jendela, misalnya, atau Anda dapat menutup aplikasi jika Anda tidak ingin menunggunya selesai.

Pendekatan berbasis asinkron menambahkan transmisi otomatis yang setara dengan daftar opsi yang dapat Anda pilih saat merancang operasi asinkron. Artinya, Anda mendapatkan semua manfaat pemrograman asinkron tradisional tetapi dengan upaya yang jauh lebih sedikit dari pengembang.

Metode asinkron lebih mudah ditulis

Kata kunci Asinkron dan Tunggu di Visual Basic adalah inti dari pemrograman asinkron. Dengan menggunakan kedua kata kunci tersebut, Anda dapat menggunakan sumber daya di .NET Framework atau Windows Runtime untuk membuat metode asinkron hampir semampu Anda membuat metode sinkron. Metode asinkron yang Anda tentukan dengan menggunakan Async dan Await disebut sebagai metode asinkron.

Contoh berikut menunjukkan metode asinkron. Hampir semua yang ada dalam kode akan terlihat sangat akrab untuk Anda. Komentar menyebut fitur yang Anda tambahkan untuk menciptakan asinkroni.

Anda dapat menemukan file contoh Windows Presentation Foundation (WPF) lengkap di akhir topik ini, dan Anda dapat mengunduh sampel dari Sampel Asinkron: Contoh dari "Pemrograman Asinkron dengan Asinkron dan Menunggu".

' Three things to note about writing an Async Function:
'  - The function has an Async modifier.
'  - Its return type is Task or Task(Of T). (See "Return Types" section.)
'  - As a matter of convention, its name ends in "Async".
Async Function AccessTheWebAsync() As Task(Of Integer)
    Using client As New HttpClient()
        ' Call and await separately.
        '  - AccessTheWebAsync can do other things while GetStringAsync is also running.
        '  - getStringTask stores the task we get from the call to GetStringAsync.
        '  - Task(Of String) means it is a task which returns a String when it is done.
        Dim getStringTask As Task(Of String) =
            client.GetStringAsync("https://learn.microsoft.com/dotnet")
        ' You can do other work here that doesn't rely on the string from GetStringAsync.
        DoIndependentWork()
        ' The Await operator suspends AccessTheWebAsync.
        '  - AccessTheWebAsync does not continue until getStringTask is complete.
        '  - Meanwhile, control returns to the caller of AccessTheWebAsync.
        '  - Control resumes here when getStringTask is complete.
        '  - The Await operator then retrieves the String result from getStringTask.
        Dim urlContents As String = Await getStringTask
        ' The Return statement specifies an Integer result.
        ' A method which awaits AccessTheWebAsync receives the Length value.
        Return urlContents.Length

    End Using

End Function

Jika AccessTheWebAsync tidak memiliki pekerjaan apa pun yang dapat dilakukan antara memanggil GetStringAsync dan menunggu penyelesaiannya, Anda dapat menyederhanakan kode Anda dengan memanggil dan menunggu dalam satu pernyataan berikut.

Dim urlContents As String = Await client.GetStringAsync()

Karakteristik berikut meringkas apa yang membuat contoh sebelumnya sebagai metode asinkron:

  • Definisi metode mencakup pengubah Async.

  • Nama metode asinkron, menurut konvensi, diakhiri dengan akhiran "Asinkron".

  • Jenis pengembalian adalah salah satu jenis berikut:

    • Task(Of TResult) jika metode Anda memiliki pernyataan pengembalian di mana operand memiliki jenis TResult.
    • Task jika metode Anda tidak memiliki pernyataan pengembalian atau memiliki pernyataan pengembalian tanpa operand.
    • Sub jika Anda menulis penanganan aktivitas asinkron.

    Untuk informasi selengkapnya, lihat "Tipe Pengembalian dan Parameter" di bagian ini kemudian.

  • Metode ini biasanya mencakup setidaknya satu ekspresi tunggu, yang menandai titik di mana metode tidak dapat dilanjutkan sampai operasi asinkron yang ditunggu selesai. Sementara itu, metode ditangguhkan, dan kontrol kembali ke pemanggil metode. Bagian berikutnya dari topik ini menggambarkan apa yang terjadi pada titik penangguhan.

Dalam metode asinkron, Anda menggunakan kata kunci dan jenis yang disediakan untuk menunjukkan apa yang ingin Anda lakukan, dan pengkompilasi melakukan sisanya, termasuk melacak apa yang harus terjadi ketika kontrol kembali ke titik tunggu dalam metode yang ditangguhkan. Beberapa proses rutin, seperti perulangan dan penanganan pengecualian, bisa sulit ditangani dalam kode asinkron tradisional. Dalam metode asinkron, Anda menulis elemen-elemen ini sebanyak yang Anda lakukan dalam solusi sinkron, dan masalahnya diselesaikan.

Untuk informasi selengkapnya tentang asinkron di versi .NET Framework sebelumnya, lihat Pemrograman Asinkron TPL dan .NET Framework Tradisional.

Apa yang terjadi dalam metode Asinkron

Hal terpenting yang perlu dipahami dalam pemrograman asinkron adalah bagaimana alur kontrol berpindah dari metode ke metode. Diagram berikut mengarahkan Anda melalui proses:

Diagram yang memperlihatkan pelacakan program asinkron.

Angka dalam diagram sesuai dengan langkah-langkah berikut:

  1. Pengendali acara memanggil dan menunggu metode asinkron AccessTheWebAsync.

  2. AccessTheWebAsync membuat instans HttpClient dan memanggil GetStringAsync metode asinkron untuk mengunduh konten situs web sebagai string.

  3. Sesuatu terjadi dalam GetStringAsync yang menangguhkan kemajuannya. Mungkin harus menunggu pengunduhan situs web atau aktivitas penghalang lainnya. Untuk menghindari pemblokiran sumber daya, GetStringAsync menghasilkan kontrol kepada pemanggilnya, AccessTheWebAsync.

    GetStringAsync mengembalikan Task(Of TResult) di mana TResult adalah string, dan AccessTheWebAsync menetapkan tugas ke getStringTask variabel. Tugas ini mewakili proses yang sedang berlangsung untuk panggilan ke GetStringAsync, dan memiliki komitmen untuk menghasilkan nilai string aktual ketika pekerjaan telah selesai.

  4. Karena getStringTask belum ditunggu, AccessTheWebAsync dapat dilanjutkan dengan pekerjaan lain yang tidak bergantung pada hasil akhir dari GetStringAsync. Pekerjaan itu diwakili oleh panggilan ke metode sinkron DoIndependentWork.

  5. DoIndependentWork adalah metode sinkron yang melakukan pekerjaannya dan kembali ke pemanggilnya.

  6. AccessTheWebAsync telah kehabisan pekerjaan yang dapat dilakukannya tanpa hasil dari getStringTask. AccessTheWebAsync selanjutnya ingin menghitung dan mengembalikan panjang string yang diunduh, tetapi metode tidak dapat menghitung nilai tersebut sampai metode memiliki string.

    Oleh karena itu, AccessTheWebAsync menggunakan operator tunggu untuk menangguhkan eksekusinya dan mengalihkan kontrol ke metode yang memanggil AccessTheWebAsync. AccessTheWebAsync mengembalikan Task(Of Integer) ke pemanggilnya. Tugas ini mewakili janji untuk menghasilkan hasil berupa bilangan bulat yang menunjukkan panjang string yang telah diunduh.

    Nota

    Jika GetStringAsync (dan oleh karena itu getStringTask) selesai sebelum AccessTheWebAsync menunggunya, kontrol tetap berada di AccessTheWebAsync. Biaya menangguhkan dan mengembalikan ke AccessTheWebAsync akan sia-sia jika proses asinkron yang disebut (getStringTask) sudah selesai dan AccessTheWebSync tidak perlu menunggu hasil akhirnya.

    Di dalam pemanggil (penanganan aktivitas dalam contoh ini), pola pemrosesan berlanjut. Pemanggil mungkin melakukan pekerjaan lain yang tidak bergantung pada hasil dari AccessTheWebAsync sebelum menanti hasil tersebut, atau pemanggil mungkin langsung menanti. Penanganan aktivitas menunggu AccessTheWebAsync, dan AccessTheWebAsync sedang menunggu GetStringAsync.

  7. GetStringAsync menyelesaikan dan menghasilkan hasil string. Hasil string tidak dikembalikan oleh panggilan ke GetStringAsync dengan cara yang mungkin Anda harapkan. (Ingat bahwa metode sudah mengembalikan tugas di langkah 3.) Sebaliknya, hasil string disimpan dalam tugas yang mewakili penyelesaian metode , getStringTask. Operator tunggu mengambil hasil dari getStringTask. Pernyataan penugasan menetapkan hasil yang diambil ke urlContents.

  8. Ketika AccessTheWebAsync memiliki hasil string, metode dapat menghitung panjang string. Kemudian pekerjaan AccessTheWebAsync juga selesai, dan penanganan aktivitas yang menunggu dapat dilanjutkan. Dalam contoh lengkap di akhir topik, Anda dapat mengonfirmasi bahwa penanganan aktivitas mengambil dan mencetak nilai hasil panjang.

Jika Anda baru menggunakan pemrograman asinkron, luangkan waktu satu menit untuk mempertimbangkan perbedaan antara perilaku sinkron dan asinkron. Metode sinkron kembali ketika pekerjaannya selesai (langkah 5), tetapi metode asinkron mengembalikan nilai tugas ketika pekerjaannya ditangguhkan (langkah 3 dan 6). Ketika metode asinkron akhirnya menyelesaikan pekerjaannya, tugas ditandai sebagai selesai dan hasilnya, jika ada, disimpan dalam tugas.

Untuk informasi selengkapnya tentang alur kontrol, lihat Alur Kontrol di Program Asinkron (Visual Basic).

Metode Asinkron API

Anda mungkin bertanya-tanya di mana menemukan metode seperti GetStringAsync yang mendukung pemrograman asinkron. .NET Framework 4.5 atau yang lebih tinggi berisi banyak anggota yang bekerja dengan Async dan Await. Anda dapat mengenali anggota ini dengan akhiran "Async" yang dilampirkan ke nama anggota dan jenis Task pengembalian atau Task(Of TResult). Misalnya, System.IO.Stream kelas berisi metode seperti CopyToAsync, , ReadAsyncdan WriteAsync bersama metode CopyTosinkron , , Readdan Write.

Windows Runtime juga berisi banyak metode yang dapat Anda gunakan dengan Async dan Await di aplikasi Windows. Untuk informasi selengkapnya dan contoh metode, lihat Memanggil API asinkron di C# atau Visual Basic, Pemrograman asinkron (aplikasi Windows Runtime), dan WhenAny: Menjembatani antara .NET Framework dan Windows Runtime.

Rangkaian Diskusi

Metode asinkron dimaksudkan sebagai operasi yang tidak memblokir. Ekspresi Await dalam metode asinkron tidak memblokir utas saat ini saat tugas yang ditunggu sedang berjalan. Sebagai gantinya, ekspresi mendaftarkan sisa metode sebagai kelanjutan dan mengembalikan kontrol ke pemanggil metode asinkron.

Async dan Await tidak menyebabkan utas tambahan dibuat. Metode asinkron tidak memerlukan multi-utas karena metode asinkron tidak berjalan pada utasnya sendiri. Metode ini berjalan di konteks sinkronisasi saat ini dan memanfaatkan waktu pada utas hanya ketika metode aktif. Anda dapat menggunakan Task.Run untuk memindahkan pekerjaan yang terikat CPU ke utas latar belakang, tetapi utas latar belakang tidak membantu proses yang hanya menunggu hasil agar tersedia.

Pendekatan berbasis asinkron untuk pemrograman asinkron lebih disukai dibandingkan pendekatan yang ada dalam hampir setiap kasus. Secara khusus, pendekatan ini lebih baik daripada BackgroundWorker untuk operasi yang bergantung pada I/O karena kodenya lebih sederhana dan Anda tidak perlu menghindari kondisi balapan. Dalam kombinasi dengan Task.Run, pemrograman asinkron lebih baik daripada BackgroundWorker untuk operasi terikat CPU karena pemrograman asinkron memisahkan detail koordinasi dalam menjalankan kode Anda dari pekerjaan yang Task.Run diteruskan ke threadpool.

Asinkron dan Await

Jika Anda menentukan bahwa metode adalah metode asinkron dengan menggunakan pengubah Asinkron , Anda mengaktifkan dua kemampuan berikut.

  • Metode asinkron yang ditandai dapat menggunakan Tunggu untuk menunjuk titik penangguhan. Operator tunggu memberi tahu pengompilasi bahwa metode asinkron tidak dapat melanjutkan melewati titik itu sampai proses asinkron yang ditunggu selesai. Sementara itu, pengendalian kembali ke pemanggil metode asinkron.

    Penangguhan sementara metode asinkron pada ekspresi Await tidak berarti keluar dari metode, dan blok kode Finally tidak dijalankan.

  • Metode asinkron yang ditandai dapat ditunggu oleh metode yang memanggilnya.

Metode asinkron biasanya berisi satu atau beberapa kemunculan Await operator, tetapi tidak adanya Await ekspresi tidak menyebabkan kesalahan kompilator. Jika metode asinkron tidak menggunakan operator Await untuk menandai titik penangguhan, metode tersebut akan dijalankan seperti metode sinkron, meskipun dengan pengubah Async. Kompilator mengeluarkan peringatan untuk metode tersebut.

Async dan Await adalah kata kunci kontekstual. Untuk informasi dan contoh selengkapnya, lihat topik berikut ini:

Jenis dan parameter pengembalian

Dalam pemrograman .NET Framework, metode asinkron biasanya mengembalikan Task atau Task(Of TResult). Di dalam metode async, operator Await diterapkan pada task yang dikembalikan dari pemanggilan metode async lainnya.

Anda menentukan Tugas (Dari TResult) sebagai jenis pengembalian jika metode berisi pernyataan Return yang menentukan operand jenis TResult.

Anda menggunakan Task sebagai jenis pengembalian jika metode tidak memiliki pernyataan pengembalian atau memiliki pernyataan pengembalian yang tidak mengembalikan operand.

Contoh berikut menunjukkan cara Anda mendeklarasikan dan memanggil metode yang mengembalikan Task(Of TResult) atau Task:

' Signature specifies Task(Of Integer)
Async Function TaskOfTResult_MethodAsync() As Task(Of Integer)

    Dim hours As Integer
    ' . . .
    ' Return statement specifies an integer result.
    Return hours
End Function

' Calls to TaskOfTResult_MethodAsync
Dim returnedTaskTResult As Task(Of Integer) = TaskOfTResult_MethodAsync()
Dim intResult As Integer = Await returnedTaskTResult
' or, in a single statement
Dim intResult As Integer = Await TaskOfTResult_MethodAsync()

' Signature specifies Task
Async Function Task_MethodAsync() As Task

    ' . . .
    ' The method has no return statement.
End Function

' Calls to Task_MethodAsync
Task returnedTask = Task_MethodAsync()
Await returnedTask
' or, in a single statement
Await Task_MethodAsync()

Setiap tugas yang dikembalikan mewakili pekerjaan yang sedang berlangsung. Tugas merangkum informasi tentang status proses asinkron dan, akhirnya, memberikan hasil akhir dari proses atau pengecualian yang terjadi jika proses tidak berhasil.

Metode asinkron juga bisa menjadi Sub metode. Jenis pengembalian ini digunakan terutama untuk menentukan penanganan aktivitas, di mana jenis pengembalian diperlukan. Penanganan aktivitas asinkron sering berfungsi sebagai titik awal untuk program asinkron.

Metode async yang merupakan Sub prosedur tidak dapat dijeda/dinantikan, dan pemanggil tidak dapat menangkap pengecualian apa pun yang mungkin dilemparkan oleh metode tersebut.

Metode asinkron tidak dapat mendeklarasikan parameter ByRef , tetapi metode ini dapat memanggil metode yang memiliki parameter tersebut.

Untuk informasi dan contoh selengkapnya, lihat Tipe Pengembalian Asinkron (Visual Basic). Untuk informasi selengkapnya tentang cara menangkap pengecualian dalam metode asinkron, lihat Try...Catch...Finally Statement.

API asinkron dalam pemrograman Windows Runtime memiliki salah satu jenis pengembalian berikut, yang mirip dengan tugas:

Untuk informasi selengkapnya dan contohnya, lihat Memanggil API asinkron di C# atau Visual Basic.

Konvensi penamaan

Menurut konvensi, Anda menambahkan "Asinkron" ke nama metode yang memiliki pengubah Async .

Anda dapat mengabaikan konvensi di mana peristiwa, kelas dasar, atau kontrak antarmuka menyarankan nama yang berbeda. Misalnya, Anda tidak boleh mengganti nama penanganan aktivitas umum, seperti Button1_Click.

Topik dan sampel terkait (Visual Studio)

Judul Deskripsi Contoh
Panduan: Mengakses Web dengan Menggunakan Asinkron dan Menunggu (Visual Basic) Menunjukkan cara mengonversi solusi WPF sinkron ke solusi WPF asinkron. Aplikasi mengunduh serangkaian situs web. Async Sample: Pemrograman Asinkron dengan Async dan Await (Visual Basic)
Cara: Memperluas Panduan Asinkron dengan Menggunakan Task.WhenAll (Visual Basic) Menambahkan Task.WhenAll ke panduan sebelumnya. Penggunaan WhenAll memulai semua unduhan secara bersamaan.
Cara: Membuat Beberapa Permintaan Web Secara Paralel dengan Menggunakan Asinkron dan Tunggu (Visual Basic) Menunjukkan cara memulai beberapa tugas secara bersamaan. Sampel Asinkron: Membuat Beberapa Permintaan Web secara Paralel
Tipe Pengembalian Asinkron (Visual Basic) Mengilustrasikan jenis yang dapat dikembalikan metode asinkron dan menjelaskan kapan setiap jenis sesuai.
Alur Kontrol dalam Program Asinkron (Visual Basic) Melacak secara rinci alur kerja kontrol melalui serangkaian ekspresi tunggu dalam program asinkron. Sampel Asinkron: Alur Kontrol dalam Program Asinkron
Fine-Tuning Aplikasi Asinkron Anda (Visual Basic) Memperlihatkan cara menambahkan fungsionalitas berikut ke solusi asinkron Anda:

- Membatalkan Tugas Asinkron atau Daftar Tugas (Visual Basic)
- Batalkan Tugas Asinkronus setelah Jangka Waktu (Visual Basic)
- Batalkan Tugas Asinkron yang Tersisa setelah Tugas Selesai (Visual Basic)
- Mulai Beberapa Tugas Asinkron dan Proses Saat Selesai (Visual Basic)
Sampel Asinkron: Menyempurnakan Aplikasi Anda
Menangani Reentrancy pada Aplikasi Asinkron (Visual Basic) Menunjukkan cara menangani situasi di mana operasi asinkron aktif dimulai ulang sementara masih berlangsung.
WhenAny: Menjembatani antara .NET Framework dan Windows Runtime Memperlihatkan cara menjembatani antara jenis Tugas di .NET Framework dan IAsyncOperations di Windows Runtime sehingga Anda dapat menggunakan WhenAny dengan metode Windows Runtime. Sampel Asinkron: Menjembatani antara .NET dan Windows Runtime (AsTask dan WhenAny)
Pembatalan Asinkron: Menjembatani antara .NET Framework dan Windows Runtime Memperlihatkan cara menjembatani antara jenis Tugas di .NET Framework dan IAsyncOperations di Windows Runtime sehingga Anda dapat menggunakan CancellationTokenSource dengan metode Windows Runtime. Sampel Asinkron: Menjembatani antara .NET dan Windows Runtime (AsTask & Cancellation)
Menggunakan Asinkron untuk Akses File (Visual Basic) Mencantumkan dan menunjukkan manfaat menggunakan async dan await untuk mengakses file.
Pola Asinkron Berbasis Tugas (TAP) Menjelaskan pola baru untuk asinkron di .NET Framework. Pola didasarkan pada tipe Task dan Task(Of TResult).

Contoh Lengkap

Kode berikut adalah file MainWindow.xaml.vb dari aplikasi Windows Presentation Foundation (WPF) yang dibahas topik ini. Anda dapat mengunduh sampel dari Sampel Asinkron: Contoh dari "Pemrograman Asinkron dengan Asinkron dan Menunggu".


Imports System.Net.Http

' Example that demonstrates Asynchronous Programming with Async and Await.
' It uses HttpClient.GetStringAsync to download the contents of a website.
' Sample Output:
' Working . . . . . . .
'
' Length of the downloaded string: 39678.

Class MainWindow

    ' Mark the event handler with Async so you can use Await in it.
    Private Async Sub StartButton_Click(sender As Object, e As RoutedEventArgs)

        ' Call and await immediately.
        ' StartButton_Click suspends until AccessTheWebAsync is done.
        Dim contentLength As Integer = Await AccessTheWebAsync()

        ResultsTextBox.Text &= $"{vbCrLf}Length of the downloaded string: {contentLength}.{vbCrLf}"

    End Sub


    ' Three things to note about writing an Async Function:
    '  - The function has an Async modifier.
    '  - Its return type is Task or Task(Of T). (See "Return Types" section.)
    '  - As a matter of convention, its name ends in "Async".
    Async Function AccessTheWebAsync() As Task(Of Integer)

        Using client As New HttpClient()

            ' Call and await separately.
            '  - AccessTheWebAsync can do other things while GetStringAsync is also running.
            '  - getStringTask stores the task we get from the call to GetStringAsync.
            '  - Task(Of String) means it is a task which returns a String when it is done.
            Dim getStringTask As Task(Of String) =
                client.GetStringAsync("https://learn.microsoft.com/dotnet")

            ' You can do other work here that doesn't rely on the string from GetStringAsync.
            DoIndependentWork()

            ' The Await operator suspends AccessTheWebAsync.
            '  - AccessTheWebAsync does not continue until getStringTask is complete.
            '  - Meanwhile, control returns to the caller of AccessTheWebAsync.
            '  - Control resumes here when getStringTask is complete.
            '  - The Await operator then retrieves the String result from getStringTask.
            Dim urlContents As String = Await getStringTask

            ' The Return statement specifies an Integer result.
            ' A method which awaits AccessTheWebAsync receives the Length value.
            Return urlContents.Length

        End Using

    End Function

    Sub DoIndependentWork()
        ResultsTextBox.Text &= $"Working . . . . . . .{vbCrLf}"
    End Sub

End Class

Lihat juga