Menggunakan objek Windows Runtime di lingkungan multithreaded

Artikel ini membahas cara .NET Framework menangani panggilan dari kode C# dan Visual Basic ke objek yang disediakan oleh Windows Runtime atau oleh komponen Windows Runtime.

Dalam .NET Framework, Anda dapat mengakses objek apa pun dari beberapa utas secara default, tanpa penanganan khusus. Yang Anda butuhkan hanyalah referensi ke objek . Di Windows Runtime, objek tersebut disebut tangkas. Sebagian besar kelas Windows Runtime lincah, tetapi beberapa kelas tidak, dan bahkan kelas tangkas mungkin memerlukan penanganan khusus.

Jika memungkinkan, runtime bahasa umum (CLR) memperlakukan objek dari sumber lain, seperti Windows Runtime, seolah-olah mereka .NET Framework objek:

  • Jika objek mengimplementasikan antarmuka IAgileObject , atau memiliki atribut MarshalingBehaviorAttribute dengan MarshalingType.Agile, CLR memperlakukannya sebagai gesit.

  • Jika CLR dapat melakukan marsekal panggilan dari utas tempat panggilan dibuat ke konteks utas objek target, itu melakukannya secara transparan.

  • Jika objek memiliki atribut MarshalingBehaviorAttribute dengan MarshalingType.None, kelas tidak memberikan informasi marsekal. CLR tidak dapat melakukan marshal panggilan, sehingga melemparkan pengecualian InvalidCastException dengan pesan yang menunjukkan bahwa objek hanya dapat digunakan dalam konteks utas tempat objek dibuat.

Bagian berikut menjelaskan efek perilaku ini pada objek dari berbagai sumber.

Objek dari komponen Windows Runtime yang ditulis dalam C# atau Visual Basic

Semua jenis dalam komponen yang dapat diaktifkan tangkas secara default.

Catatan

Kelincahan tidak menyiratkan keamanan benang. Di Windows Runtime dan .NET Framework, sebagian besar kelas tidak aman karena keamanan utas memiliki biaya performa, dan sebagian besar objek tidak pernah diakses oleh beberapa utas. Lebih efisien untuk menyinkronkan akses ke objek individual (atau menggunakan kelas aman utas) hanya seperlunya.

Saat Anda menulis komponen Windows Runtime, Anda dapat mengambil alih default. Lihat antarmuka ICustomQueryInterface dan antarmuka IAgileObject .

Objek dari Windows Runtime

Sebagian besar kelas di Windows Runtime lincah, dan CLR memperlakukannya sebagai tangkas. Dokumentasi untuk kelas-kelas ini mencantumkan "MarshalingBehaviorAttribute(Agile)" di antara atribut kelas. Namun, anggota beberapa kelas tangkas ini, seperti kontrol XAML, melemparkan pengecualian jika tidak dipanggil pada utas UI. Misalnya, kode berikut mencoba menggunakan utas latar belakang untuk mengatur properti tombol yang diklik. Properti Konten tombol melemparkan pengecualian.

private async void Button_Click_2(object sender, RoutedEventArgs e)
{
    Button b = (Button) sender;
    await Task.Run(() => {
        b.Content += ".";
    });
}
Private Async Sub Button_Click_2(sender As Object, e As RoutedEventArgs)
    Dim b As Button = CType(sender, Button)
    Await Task.Run(Sub()
                       b.Content &= "."
                   End Sub)
End Sub

Anda dapat mengakses tombol dengan aman dengan menggunakan properti Dispatcher-nya , atau Dispatcher properti objek apa pun yang ada dalam konteks utas UI (seperti halaman tempat tombol berada). Kode berikut menggunakan metode RunAsync objek CoreDispatcher untuk mengirimkan panggilan pada utas UI.

private async void Button_Click_2(object sender, RoutedEventArgs e)
{
    Button b = (Button) sender;
    await b.Dispatcher.RunAsync(
        Windows.UI.Core.CoreDispatcherPriority.Normal,
        () => {
            b.Content += ".";
    });
}

Private Async Sub Button_Click_2(sender As Object, e As RoutedEventArgs)
    Dim b As Button = CType(sender, Button)
    Await b.Dispatcher.RunAsync(
        Windows.UI.Core.CoreDispatcherPriority.Normal,
        Sub()
            b.Content &= "."
        End Sub)
End Sub

Catatan

Properti Dispatcher tidak melemparkan pengecualian ketika dipanggil dari utas lain.

Masa pakai objek Windows Runtime yang dibuat pada utas UI dibatasi oleh masa pakai utas. Jangan mencoba mengakses objek pada utas UI setelah jendela ditutup.

Jika Anda membuat kontrol Anda sendiri dengan mewarisi kontrol XAML, atau dengan menyusun sekumpulan kontrol XAML, kontrol Anda gesit karena merupakan objek .NET Framework. Namun, jika memanggil anggota kelas dasar atau kelas konstituennya, atau jika Anda memanggil anggota yang diwariskan, anggota tersebut akan melemparkan pengecualian ketika mereka dipanggil dari utas apa pun kecuali utas UI.

Kelas yang tidak dapat dijadikan marshal

Kelas Windows Runtime yang tidak menyediakan informasi marsekal memiliki atribut MarshalingBehaviorAttribute dengan MarshalingType.None. Dokumentasi untuk kelas seperti itu mencantumkan "MarshalingBehaviorAttribute(None)" di antara atributnya.

Kode berikut membuat objek CameraCaptureUI pada utas UI, lalu mencoba mengatur properti objek dari utas kumpulan utas. CLR tidak dapat melakukan marshal panggilan, dan melempar pengecualian System.InvalidCastException dengan pesan yang menunjukkan bahwa objek hanya dapat digunakan dalam konteks threading tempat objek dibuat.

Windows.Media.Capture.CameraCaptureUI ccui;

private async void Button_Click_1(object sender, RoutedEventArgs e)
{
    ccui = new Windows.Media.Capture.CameraCaptureUI();

    await Task.Run(() => {
        ccui.PhotoSettings.AllowCropping = true;
    });
}

Private ccui As Windows.Media.Capture.CameraCaptureUI

Private Async Sub Button_Click_1(sender As Object, e As RoutedEventArgs)
    ccui = New Windows.Media.Capture.CameraCaptureUI()

    Await Task.Run(Sub()
                       ccui.PhotoSettings.AllowCropping = True
                   End Sub)
End Sub

Dokumentasi untuk CameraCaptureUI juga mencantumkan "ThreadingAttribute(STA)" di antara atribut kelas, karena harus dibuat dalam konteks utas tunggal seperti utas UI.

Jika Anda ingin mengakses objek CameraCaptureUI dari utas lain, Anda dapat menyimpan objek CoreDispatcher untuk utas UI dan menggunakannya nanti untuk mengirimkan panggilan pada utas tersebut. Atau Anda dapat memperoleh dispatcher dari objek XAML seperti halaman, seperti yang ditunjukkan dalam kode berikut.

Windows.Media.Capture.CameraCaptureUI ccui;

private async void Button_Click_3(object sender, RoutedEventArgs e)
{
    ccui = new Windows.Media.Capture.CameraCaptureUI();

    await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal,
        () => {
            ccui.PhotoSettings.AllowCropping = true;
        });
}

Dim ccui As Windows.Media.Capture.CameraCaptureUI

Private Async Sub Button_Click_3(sender As Object, e As RoutedEventArgs)

    ccui = New Windows.Media.Capture.CameraCaptureUI()

    Await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal,
                                Sub()
                                    ccui.PhotoSettings.AllowCropping = True
                                End Sub)
End Sub

Objek dari komponen Windows Runtime yang ditulis dalam C++

Secara default, kelas dalam komponen yang dapat diaktifkan tangkas. Namun, C++ memungkinkan sejumlah besar kontrol atas model utas dan perilaku marshaling. Seperti yang dijelaskan sebelumnya dalam artikel ini, CLR mengenali kelas agile, mencoba melakukan panggilan marshal ketika kelas tidak gesar, dan melempar pengecualian System.InvalidCastException ketika kelas tidak memiliki informasi marshaling.

Untuk objek yang berjalan pada utas UI dan melemparkan pengecualian ketika dipanggil dari utas selain utas UI, Anda dapat menggunakan objek CoreDispatcher utas UI untuk mengirimkan panggilan.

Lihat juga

Panduan C#

Panduan Visual Basic