Pindah ke C++/WinRT dari C#

Tip

Jika Anda telah membaca topik ini sebelumnya, dan Anda kembali ke topik ini dengan mempertimbangkan tugas tertentu, maka Anda dapat melompat ke bagian Temukan konten berdasarkan tugas yang Anda lakukan di topik ini.

Topik ini secara komprehensif membuat katalog detail teknis yang terlibat dalam porting kode sumber dalam proyek C# setara di C++/WinRT.

Untuk studi kasus porting salah satu sampel aplikasi Platform Windows Universal (UWP), lihat topik pendamping Memindahkan sampel Clipboard ke C++/WinRT dari C#. Anda dapat memperoleh praktik dan pengalaman porting dengan mengikuti panduan tersebut, dan memindahkan sampel untuk diri Anda sendiri saat Anda pergi.

Cara mempersiapkan, dan apa yang diharapkan

Studi kasus Memindahkan sampel Clipboard ke C++/WinRT dari C# menggambarkan contoh jenis keputusan desain perangkat lunak yang akan Anda buat saat memindahkan proyek ke C++/WinRT. Jadi, ada baiknya mempersiapkan porting dengan mendapatkan pemahaman yang kuat tentang cara kerja kode yang ada. Dengan begitu, Anda akan mendapatkan gambaran umum yang baik tentang fungsionalitas aplikasi, dan struktur kode, dan kemudian keputusan yang Anda buat akan selalu membawa Anda maju, dan ke arah yang benar.

Dalam hal jenis perubahan port apa yang diharapkan, Anda dapat mengelompokkannya ke dalam empat kategori.

  • Port proyeksi bahasa. Windows Runtime (WinRT) diproyeksikan ke dalam berbagai bahasa pemrograman. Masing-masing proyeksi bahasa dirancang untuk merasa idiomatik dengan bahasa pemrograman yang dimaksud. Untuk C#, beberapa jenis Windows Runtime diproyeksikan sebagai jenis .NET. Jadi, misalnya Anda akan menerjemahkan System.Collections.Generic.IReadOnlyList<T> kembali ke Windows.Foundation.Collections.IVectorView<T>. Juga dalam C#, beberapa operasi Windows Runtime diproyeksikan sebagai fitur bahasa C# yang nyaman. Contohnya adalah bahwa dalam C# Anda menggunakan += sintaks operator untuk mendaftarkan delegasi penanganan peristiwa. Jadi Anda akan menerjemahkan fitur bahasa seperti itu kembali ke operasi mendasar yang sedang dilakukan (pendaftaran peristiwa, dalam contoh ini).
  • Sintaks bahasa port. Banyak dari perubahan ini adalah transformasi mekanis sederhana, menggantikan satu simbol untuk yang lain. Misalnya, mengubah titik (.) menjadi titik dua (::).
  • Prosedur bahasa port. Beberapa di antaranya bisa menjadi perubahan sederhana dan berulang (seperti myObject.MyPropertymyObject.MyProperty()). Yang lain membutuhkan perubahan yang lebih dalam (misalnya, memindahkan prosedur yang melibatkan penggunaan System.Text.StringBuilder ke salah satu yang melibatkan penggunaan std::wostringstream).
  • Tugas terkait porting yang khusus untuk C++/WinRT. Detail tertentu dari Windows Runtime diurus secara implisit oleh C#, di belakang layar. Detail tersebut dilakukan secara eksplisit di C++/WinRT. Contohnya adalah Anda menggunakan .idl file untuk menentukan kelas runtime Anda.

Setelah indeks berbasis tugas yang mengikuti, bagian lainnya dalam topik ini disusun sesuai dengan taksonomi di atas.

Menemukan konten berdasarkan tugas yang Anda lakukan

Tugas Konten
Menulis komponen Windows Runtime (WRC) Fungsionalitas tertentu dapat dicapai (atau API tertentu yang disebut) hanya dengan C++. Anda dapat memperhitungkan fungsionalitas tersebut ke dalam C++/WinRT WRC, lalu menggunakan WRC dari (misalnya) aplikasi C#. Lihat komponen Windows Runtime dengan C++/WinRT dan Jika Anda menulis kelas runtime dalam komponen Windows Runtime.
Port metode asinkron Ini adalah ide yang baik untuk baris pertama metode asinkron di kelas auto lifetime = get_strong(); runtime C++/WinRT menjadi (lihat Brankas mengakses pointer ini dalam koroutine anggota kelas).

Porting dari Task, lihat Tindakan asinkron.
Porting dari Task<T>, lihat Operasi asinkron.
Porting dari async void, lihat Metode fire-and-forget.
Port kelas Pertama, tentukan apakah kelas perlu menjadi kelas runtime, atau apakah itu bisa menjadi kelas biasa. Untuk membantu Anda memutuskannya, lihat awal API Penulis dengan C++/WinRT. Kemudian, lihat tiga baris berikutnya di bawah ini.
Port kelas runtime Kelas yang berbagi fungsionalitas di luar aplikasi C++, atau kelas yang digunakan dalam pengikatan data XAML. Lihat Jika Anda menulis kelas runtime dalam komponen Windows Runtime, atau Jika Anda menulis kelas runtime untuk direferensikan di antarmuka pengguna XAML Anda.

Tautan tersebut menjelaskan ini secara lebih rinci, tetapi kelas runtime harus dideklarasikan dalam IDL. Jika proyek Anda sudah berisi file IDL (misalnya, Project.idl), maka kami sarankan Anda mendeklarasikan kelas runtime baru dalam file tersebut. Di IDL, deklarasikan metode dan anggota data apa pun yang akan digunakan di luar aplikasi Anda, atau yang akan digunakan di XAML. Setelah memperbarui file IDL, membangun kembali, dan melihat file stub yang dihasilkan (.h dan .cpp) di folder proyek Generated Files Anda (Dalam Penjelajah Solusi, dengan simpul proyek dipilih, pastikan Perlihatkan Semua File diaktifkan). Bandingkan file stub dengan file yang sudah ada di proyek Anda, menambahkan file atau menambahkan/memperbarui tanda tangan fungsi seperlunya. Sintaks file stub selalu benar, jadi kami sarankan Anda menggunakannya untuk meminimalkan kesalahan build. Setelah stub dalam proyek Anda cocok dengan yang ada di file stub, Anda dapat melanjutkan dan mengimplementasikannya dengan memindahkan kode C#.
Port kelas biasa Lihat Jika Anda tidak menulis kelas runtime.
IDL Penulis Pengantar Microsoft Interface Definition Language 3.0
Jika Anda menulis kelas runtime yang akan direferensikan di antarmuka pengguna XAML Anda
Mengkonsumsi objek dari markup XAML
Menentukan kelas runtime Anda di IDL
Port koleksi Koleksi dengan C++/WinRT
Membuat sumber data tersedia untuk markup XAML
Kontainer asosiatif
Akses anggota vektor
Port peristiwa Penangan aktivitas mendelegasikan sebagai anggota kelas
Mencabut delegasi penanganan aktivitas
Port metode Dari C#: private async void SampleButton_Tapped(object sender, Windows.UI.Xaml.Input.TappedRoutedEventArgs e) { ... }
Ke file C++/WinRT .h : fire_and_forget SampleButton_Tapped(IInspectable const&, RoutedEventArgs const&);
Ke file C++/WinRT .cpp : fire_and_forget OcrFileImage::SampleButton_Tapped(IInspectable const&, RoutedEventArgs const&) {...}
String port Penanganan string di C++/WinRT
ToString
Pembangun string
Tinju dan membuka kotak string
Konversi jenis (pengecoran jenis) C#: o.ToString()
C++/WinRT: to_hstring(static_cast<int>(o))
Lihat juga ToString.

C#: (Value)o
C++/WinRT: unbox_value<Value>(o)
Melempar jika pembukaan kotak gagal. Lihat juga Tinju dan buka kotak.

C#: o as Value? ?? fallback
C++/WinRT: unbox_value_or<Value>(o, fallback)
Mengembalikan fallback jika pembatalan kotak gagal. Lihat juga Tinju dan buka kotak.

C#: (Class)o
C++/WinRT: o.as<Class>()
Melempar jika konversi gagal.

C#: o as Class
C++/WinRT: o.try_as<Class>()
Mengembalikan null jika konversi gagal.

Perubahan yang melibatkan proyeksi bahasa

Kategori C# C++/WinRT Lihat juga
Objek yang tidak dititik object, atau System.Object Windows::Foundation::IInspectable Porting metode EnableClipboardContentChangedNotifications
Namespace proyeksi using System; using namespace Windows::Foundation;
using System.Collections.Generic; using namespace Windows::Foundation::Collections;
Ukuran koleksi collection.Count collection.Size() Porting metode BuildClipboardFormatsOutputString
Jenis koleksi umum IList<T>, dan Tambahkan untuk menambahkan elemen. IVector<T>, dan Tambahkan untuk menambahkan elemen. Jika Anda menggunakan std::vector di mana saja, maka push_back untuk menambahkan elemen.
Jenis koleksi baca-saja IReadOnlyList<T> IVectorView<T> Porting metode BuildClipboardFormatsOutputString
Penangan aktivitas mendelegasikan sebagai anggota kelas myObject.EventName += Handler; token = myObject.EventName({ get_weak(), &Class::Handler }); Porting metode EnableClipboardContentChangedNotifications
Mencabut delegasi penanganan aktivitas myObject.EventName -= Handler; myObject.EventName(token); Porting metode EnableClipboardContentChangedNotifications
Kontainer asosiatif IDictionary<K, V> IMap<K, V>
Akses anggota vektor x = v[i];
v[i] = x;
x = v.GetAt(i);
v.SetAt(i, x);

Mendaftarkan/mencabut penanganan aktivitas

Di C++/WinRT, Anda memiliki beberapa opsi sindikat untuk mendaftarkan/mencabut delegasi penanganan aktivitas, seperti yang dijelaskan dalam Menangani peristiwa dengan menggunakan delegasi di C++/WinRT. Lihat juga Porting metode EnableClipboardContentChangedNotifications.

Terkadang, misalnya ketika penerima peristiwa (objek yang menangani peristiwa) akan dihancurkan, Anda akan ingin mencabut penanganan aktivitas sehingga sumber peristiwa (objek yang menaikkan peristiwa) tidak memanggil ke objek yang dihancurkan. Lihat Mencabut delegasi terdaftar. Dalam kasus seperti itu, buat variabel anggota event_token untuk penanganan aktivitas Anda. Misalnya, lihat Porting metode EnableClipboardContentChangedNotifications.

Anda juga dapat mendaftarkan penanganan aktivitas di markup XAML.

<Button x:Name="OpenButton" Click="OpenButton_Click" />

Di C#, metode OpenButton_Click Anda dapat bersifat privat, dan XAML masih dapat menghubungkannya ke peristiwa ButtonBase.Click yang dinaikkan oleh OpenButton.

Di C++/WinRT, metode OpenButton_Click Anda harus publik dalam jenisimplementasi Anda jika Anda ingin mendaftarkannya di markup XAML. Jika Anda mendaftarkan penanganan aktivitas hanya dalam kode imperatif, maka penanganan aktivitas tidak perlu publik.

namespace winrt::MyProject::implementation
{
    struct MyPage : MyPageT<MyPage>
    {
        void OpenButton_Click(
            winrt::Windows:Foundation::IInspectable const& sender,
            winrt::Windows::UI::Xaml::RoutedEventArgs const& args);
    }
};

Atau, Anda dapat menjadikan halaman XAML pendaftaran sebagai teman dari jenis implementasi Anda, dan OpenButton_Click privat.

namespace winrt::MyProject::implementation
{
    struct MyPage : MyPageT<MyPage>
    {
    private:
        friend MyPageT;
        void OpenButton_Click(
            winrt::Windows:Foundation::IInspectable const& sender,
            winrt::Windows::UI::Xaml::RoutedEventArgs const& args);
    }
};

Salah satu skenario terakhir adalah di mana proyek C# yang Anda porting mengikat ke penanganan aktivitas dari markup (untuk latar belakang lainnya tentang skenario tersebut, lihat Fungsi dalam x:Bind).

<Button x:Name="OpenButton" Click="{x:Bind OpenButton_Click}" />

Anda hanya bisa mengubah markup itu menjadi lebih sederhana Click="OpenButton_Click". Atau, jika mau, Anda dapat menyimpan markup tersebut apa adanya. Yang harus Anda lakukan untuk mendukungnya adalah mendeklarasikan penanganan aktivitas di IDL.

void OpenButton_Click(Object sender, Windows.UI.Xaml.RoutedEventArgs e);

Catatan

Deklarasikan fungsi seolah-olah void Anda mengimplementasikannya sebagai Api dan lupakan.

Perubahan yang melibatkan sintaks bahasa

Kategori C# C++/WinRT Lihat juga
Pengubah akses public \<member\> public:
    \<member\>
Porting metode Button_Click
Mengakses anggota data this.variable this->variable  
Tindakan asinkron async Task ... IAsyncAction ... Antarmuka IAsyncAction, Konkurensi, dan operasi asinkron dengan C++/WinRT
Operasi asinkron async Task<T> ... IAsyncOperation<T> ... Antarmuka IAsyncOperation, Konkurensi, dan operasi asinkron dengan C++/WinRT
Metode Fire-and-forget (menyiratkan asinkron) async void ... winrt::fire_and_forget ... Porting metode CopyButton_Click, Api dan lupakan
Mengakses konstanta enumerasi E.Value E::Value Porting metode DisplayChangedFormats
Menunggu secara kooperatif await ... co_await ... Porting metode CopyButton_Click
Kumpulan jenis yang diproyeksikan sebagai bidang privat private List<MyRuntimeClass> myRuntimeClasses = new List<MyRuntimeClass>(); std::vector
<MyNamespace::MyRuntimeClass>
m_myRuntimeClasses;
Konstruksi GUID private static readonly Guid myGuid = new Guid("C380465D-2271-428C-9B83-ECEA3B4A85C1"); winrt::guid myGuid{ 0xC380465D, 0x2271, 0x428C, { 0x9B, 0x83, 0xEC, 0xEA, 0x3B, 0x4A, 0x85, 0xC1} };
Pemisah namespace A.B.T A::B::T
Null null nullptr Porting metode UpdateStatus
Mendapatkan objek jenis typeof(MyType) winrt::xaml_typename<MyType>() Porting properti Skenario
Deklarasi parameter untuk metode MyType MyType const& Pengoperasian parameter
Deklarasi parameter untuk metode asinkron MyType MyType Pengoperasian parameter
Memanggil metode statis T.Method() T::Method()
String string, atau System.String winrt::hstring Penanganan string di C++/WinRT
String literal "a string literal" L"a string literal" Memindahkan konstruktor, Saat Ini, dan FEATURE_NAME
Tipe yang disimpulkan (atau disimpulkan) var auto Porting metode BuildClipboardFormatsOutputString
Menggunakan direktif using A.B.C; using namespace A::B::C; Memindahkan konstruktor, Saat Ini, dan FEATURE_NAME
Verbatim/string mentah literal @"verbatim string literal" LR"(raw string literal)" Porting metode DisplayToast

Catatan

Jika file header tidak berisi using namespace direktif untuk namespace tertentu, maka Anda harus sepenuhnya memenuhi syarat semua nama jenis untuk namespace tersebut; atau setidaknya memenuhi syarat untuk pengkompilasi untuk menemukannya. Misalnya, lihat Porting metode DisplayToast.

Porting kelas dan anggota

Anda harus memutuskan, untuk setiap jenis C#, apakah akan memindahkannya ke jenis Windows Runtime, atau ke kelas/struct/enumerasi C++ biasa. Untuk informasi selengkapnya, dan contoh terperinci yang mengilustrasikan cara membuat keputusan tersebut, lihat Memindahkan sampel Clipboard ke C++/WinRT dari C#.

Properti C# biasanya menjadi fungsi pengakses, fungsi mutator, dan anggota data cadangan. Untuk informasi selengkapnya, dan contohnya, lihat Porting properti IsClipboardContentChangedEnabled.

Untuk bidang non-statis, jadikan mereka anggota data dari jenis implementasi Anda.

Bidang statis C# menjadi aksesor statis C++/WinRT dan/atau fungsi mutator. Untuk informasi selengkapnya, dan contohnya, lihat Memindahkan konstruktor, Saat Ini, dan FEATURE_NAME.

Untuk fungsi anggota, sekali lagi, Anda harus memutuskan untuk masing-masing apakah fungsi tersebut termasuk dalam IDL atau tidak, atau apakah itu fungsi anggota publik atau privat dari jenis implementasi Anda. Untuk informasi selengkapnya, dan contoh cara memutuskan, lihat IDL untuk jenis MainPage.

Porting markup XAML, dan file aset

Dalam kasus Porting sampel Clipboard ke C++/WinRT dari C#, kami dapat menggunakan markup XAML yang sama (termasuk sumber daya) dan file aset di seluruh C# dan proyek C++/WinRT. Dalam beberapa kasus, pengeditan pada markup akan diperlukan untuk mencapainya. Lihat Menyalin XAML dan gaya yang diperlukan untuk menyelesaikan port MainPage.

Perubahan yang melibatkan prosedur dalam bahasa

Kategori C# C++/WinRT Lihat juga
Manajemen seumur hidup dalam metode asinkron T/A auto lifetime{ get_strong() }; atau
auto lifetime = get_strong();
Porting metode CopyButton_Click
Pembuangan using (var t = v) auto t{ v };
t.Close(); // or let wrapper destructor do the work
Porting metode CopyImage
Membuat objek new MyType(args) MyType{ args } atau
MyType(args)
Porting properti Skenario
Membuat referensi yang tidak diinisialisasi MyType myObject; MyType myObject{ nullptr }; atau
MyType myObject = nullptr;
Memindahkan konstruktor, Saat Ini, dan FEATURE_NAME
Membuat objek menjadi variabel dengan args var myObject = new MyType(args); auto myObject{ MyType{ args } }; Atau
auto myObject{ MyType(args) }; Atau
auto myObject = MyType{ args }; Atau
auto myObject = MyType(args); Atau
MyType myObject{ args }; Atau
MyType myObject(args);
Porting metode Footer_Click
Buat objek menjadi variabel tanpa arg var myObject = new T(); MyType myObject; Porting metode BuildClipboardFormatsOutputString
Shorthand inisialisasi objek var p = new FileOpenPicker{
    ViewMode = PickerViewMode.List
};
FileOpenPicker p;
p.ViewMode(PickerViewMode::List);
Operasi vektor massal var p = new FileOpenPicker{
    FileTypeFilter = { ".png", ".jpg", ".gif" }
};
FileOpenPicker p;
p.FileTypeFilter().ReplaceAll({ L".png", L".jpg", L".gif" });
Porting metode CopyButton_Click
Iterasi melalui koleksi foreach (var v in c) for (auto&& v : c) Porting metode BuildClipboardFormatsOutputString
Menangkap pengecualian catch (Exception ex) catch (winrt::hresult_error const& ex) Porting metode PasteButton_Click
Detail pengecualian ex.Message ex.message() Porting metode PasteButton_Click
Mendapatkan nilai properti myObject.MyProperty myObject.MyProperty() Porting metode NotifyUser
Mengatur nilai properti myObject.MyProperty = value; myObject.MyProperty(value);
Menaikkan nilai properti myObject.MyProperty += v; myObject.MyProperty(thing.Property() + v);
Untuk string, beralihlah ke penyusun
ToString() myObject.ToString() winrt::to_hstring(myObject) ToString()
String bahasa ke string Runtime Windows T/A winrt::hstring{ s }
Pembangun string StringBuilder builder;
builder.Append(...);
std::wostringstream builder;
builder << ...;
Pembangun string
Interpolasi string $"{i++}) {s.Title}" winrt::to_hstring, dan/atau winrt::hstring::operator+ Porting metode OnNavigatedTo
String kosong untuk perbandingan System.String.Empty winrt::hstring::empty Porting metode UpdateStatus
Membuat string kosong var myEmptyString = String.Empty; winrt::hstring myEmptyString{ L"" };
Operasi kamus map[k] = v; // replaces any existing
v = map[k]; // throws if not present
map.ContainsKey(k)
map.Insert(k, v); // replaces any existing
v = map.Lookup(k); // throws if not present
map.HasKey(k)
Konversi jenis (melemparkan kegagalan) (MyType)v v.as<MyType>() Porting metode Footer_Click
Konversi jenis (null pada kegagalan) v as MyType v.try_as<MyType>() Porting metode PasteButton_Click
Elemen XAML dengan x:Name adalah properti MyNamedElement MyNamedElement() Memindahkan konstruktor, Saat Ini, dan FEATURE_NAME
Beralih ke utas UI CoreDispatcher.RunAsync CoreDispatcher.RunAsync, atau winrt::resume_foreground Porting metode NotifyUser, dan Porting metode HistoryAndRoaming
Konstruksi elemen UI dalam kode imperatif di halaman XAML Lihat konstruksi elemen UI Lihat konstruksi elemen UI

Bagian berikut masuk ke detail selengkapnya mengenai beberapa item dalam tabel.

Konstruksi elemen UI

Contoh kode ini menunjukkan konstruksi elemen UI dalam kode imperatif halaman XAML.

var myTextBlock = new TextBlock()
{
    Text = "Text",
    Style = (Windows.UI.Xaml.Style)this.Resources["MyTextBlockStyle"]
};
TextBlock myTextBlock;
myTextBlock.Text(L"Text");
myTextBlock.Style(
    winrt::unbox_value<Windows::UI::Xaml::Style>(
        Resources().Lookup(
            winrt::box_value(L"MyTextBlockStyle")
        )
    )
);

ToString()

Jenis C# menyediakan metode Object.ToString .

int i = 2;
var s = i.ToString(); // s is a System.String with value "2".

C++/WinRT tidak secara langsung menyediakan fasilitas ini, tetapi Anda dapat beralih ke alternatif.

int i{ 2 };
auto s{ std::to_wstring(i) }; // s is a std::wstring with value L"2".

C++/WinRT juga mendukung winrt::to_hstring untuk sejumlah jenis yang terbatas. Anda harus menambahkan kelebihan beban untuk jenis tambahan apa pun yang ingin Anda stringifikasi.

Bahasa Stringify int Enum stringify
C# string result = "hello, " + intValue.ToString();
string result = $"hello, {intValue}";
string result = "status: " + status.ToString();
string result = $"status: {status}";
C++/WinRT hstring result = L"hello, " + to_hstring(intValue); // must define overload (see below)
hstring result = L"status: " + to_hstring(status);

Dalam kasus stringifying enum, Anda harus memberikan implementasi winrt::to_hstring.

namespace winrt
{
    hstring to_hstring(StatusEnum status)
    {
        switch (status)
        {
        case StatusEnum::Success: return L"Success";
        case StatusEnum::AccessDenied: return L"AccessDenied";
        case StatusEnum::DisabledByPolicy: return L"DisabledByPolicy";
        default: return to_hstring(static_cast<int>(status));
        }
    }
}

Stringifikasi ini sering digunakan secara implisit oleh pengikatan data.

<TextBlock>
You have <Run Text="{Binding FlowerCount}"/> flowers.
</TextBlock>
<TextBlock>
Most recent status is <Run Text="{x:Bind LatestOperation.Status}"/>.
</TextBlock>

Pengikatan ini akan melakukan winrt::to_hstring properti terikat. Dalam kasus contoh kedua ( StatusEnum), Anda harus menyediakan kelebihan beban Winrt::to_hstring Anda sendiri, jika tidak, Anda akan mendapatkan kesalahan pengkompilasi.

Lihat juga Porting metode Footer_Click.

Pembangun string

Untuk pembuatan string, C# memiliki jenis StringBuilder bawaan.

Kategori C# C++/WinRT
Pembangun string StringBuilder builder;
builder.Append(...);
std::wostringstream builder;
builder << ...;
Menambahkan string Runtime Windows, mempertahankan null builder.Append(s); builder << std::wstring_view{ s };
Menambahkan baris baru builder.Append(Environment.NewLine); builder << std::endl;
Mengakses hasil s = builder.ToString(); ws = builder.str();

Lihat juga Porting metode BuildClipboardFormatsOutputString, dan Porting metode DisplayChangedFormats.

Menjalankan kode pada utas UI utama

Contoh ini diambil dari sampel pemindai Barcode.

Ketika Anda ingin melakukan pekerjaan pada utas UI utama dalam proyek C#, Anda biasanya menggunakan metode CoreDispatcher.RunAsync , seperti ini.

private async void Watcher_Added(DeviceWatcher sender, DeviceInformation args)
{
    await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
    {
        // Do work on the main UI thread here.
    });
}

Jauh lebih mudah untuk mengekspresikannya di C++/WinRT. Perhatikan bahwa kami menerima parameter berdasarkan nilai pada asumsi, kami akan ingin mengaksesnya setelah titik penangguhan pertama ( co_await, dalam hal ini). Untuk informasi selengkapnya, lihat Parameter-passing.

winrt::fire_and_forget Watcher_Added(DeviceWatcher sender, winrt::DeviceInformation args)
{
    co_await Dispatcher();
    // Do work on the main UI thread here.
}

Jika Anda perlu melakukan pekerjaan dengan prioritas selain default, lihat fungsi winrt::resume_foreground , yang memiliki kelebihan beban yang mengambil prioritas. Untuk contoh kode yang menunjukkan cara menunggu panggilan ke winrt::resume_foreground, lihat Pemrograman dengan mempertimbangkan afinitas utas.

Menentukan kelas runtime Anda di IDL

Lihat IDL untuk jenis MainPage, dan Mengonsolidasikan file Anda.idl.

Sertakan file header namespace layanan Windows C++/WinRT yang Anda butuhkan

Di C++/WinRT, setiap kali Anda ingin menggunakan jenis dari namespace Windows, Anda perlu menyertakan file header namespace layanan Windows C++/WinRT yang sesuai. Misalnya, lihat Porting metode NotifyUser.

Boxing dan Unboxing

C# secara otomatis mengetikkan skalar ke dalam objek. C++/WinRT mengharuskan Anda untuk memanggil fungsi winrt::box_value secara eksplisit. Kedua bahasa mengharuskan Anda untuk membuka kotak secara eksplisit. Lihat Tinju dan buka kotak dengan C++/WinRT.

Dalam tabel berikut, kita akan menggunakan definisi ini.

C# C++/WinRT
int i; int i;
string s; winrt::hstring s;
object o; IInspectable o;
Operasi C# C++/WinRT
Boxing o = 1;
o = "string";
o = box_value(1);
o = box_value(L"string");
Membuka kemasan i = (int)o;
s = (string)o;
i = unbox_value<int>(o);
s = unbox_value<winrt::hstring>(o);

C++/CX dan C# menimbulkan pengecualian jika Anda mencoba membuka kotak penunjuk null ke jenis nilai. C++/WinRT menganggap ini sebagai kesalahan pemrograman, dan mengalami crash. Di C++/WinRT, gunakan fungsi winrt::unbox_value_or jika Anda ingin menangani kasus di mana objek bukan dari jenis yang Anda pikirkan.

Skenario C# C++/WinRT
Batalkan kotak bilangan bulat yang diketahui i = (int)o; i = unbox_value<int>(o);
Jika o null System.NullReferenceException Kecelakaan
Jika o bukan int berkotak System.InvalidCastException Kecelakaan
Batalkan kotak masuk, gunakan fallback jika null; crash jika ada yang lain i = o != null ? (int)o : fallback; i = o ? unbox_value<int>(o) : fallback;
Batalkan kotak int jika memungkinkan; gunakan fallback untuk hal lain i = as int? ?? fallback; i = unbox_value_or<int>(o, fallback);

Misalnya, lihat Porting metode OnNavigatedTo, dan Porting metode Footer_Click.

Tinju dan membuka kotak string

String dalam beberapa cara adalah jenis nilai, dan dengan cara lain jenis referensi. C# dan C++/WinRT memperlakukan string secara berbeda.

HSTRING jenis ABI adalah penunjuk ke string yang dihitung referensi. Tetapi tidak berasal dari IInspectable, jadi itu bukan objek secara teknis. Selain itu, HSTRING null mewakili string kosong. Tinju hal-hal yang tidak berasal dari IInspectable dilakukan dengan membungkusnya di dalam IReference<T>, dan Windows Runtime menyediakan implementasi standar dalam bentuk objek PropertyValue (jenis kustom dilaporkan sebagai PropertyType::OtherType).

C# mewakili string Runtime Windows sebagai jenis referensi; sementara C++/WinRT memproyeksikan string sebagai jenis nilai. Ini berarti bahwa string null kotak dapat memiliki representasi yang berbeda tergantung bagaimana Anda sampai di sana.

Perilaku C# C++/WinRT
Deklarasi object o;
string s;
IInspectable o;
hstring s;
Kategori jenis string Jenis referensi Jenis nilai
proyek HSTRING null sebagai "" hstring{}
Apakah null dan "" identik? Tidak Ya
Validitas null s = null;
s.Length meningkatkan NullReferenceException
s = hstring{};
s.size() == 0 (valid)
Jika Anda menetapkan string null ke objek o = (string)null;
o == null
o = box_value(hstring{});
o != nullptr
Jika Anda menetapkan "" ke objek o = "";
o != null
o = box_value(hstring{L""});
o != nullptr

Tinju dasar dan pembukaan kotak.

Operasi C# C++/WinRT
Kotak untai (karakter) o = s;
String kosong menjadi objek non-null.
o = box_value(s);
String kosong menjadi objek non-null.
Batalkan kotak string yang diketahui s = (string)o;
Objek null menjadi string null.
InvalidCastException jika bukan string.
s = unbox_value<hstring>(o);
Objek null mengalami crash.
Crash jika bukan string.
Batalkan kotak kemungkinan string s = o as string;
Objek null atau non-string menjadi string null.

ATAU

s = o as string ?? fallback;
Null atau non-string menjadi fallback.
String kosong dipertahankan.
s = unbox_value_or<hstring>(o, fallback);
Null atau non-string menjadi fallback.
String kosong dipertahankan.

Membuat kelas tersedia untuk ekstensi markup {Binding}

Jika Anda ingin menggunakan ekstensi markup {Binding} ke pengikatan data ke tipe data Anda, maka lihat Objek pengikatan yang dideklarasikan menggunakan {Binding}.

Mengkonsumsi objek dari markup XAML

Dalam proyek C#, Anda dapat menggunakan anggota privat dan elemen bernama dari markup XAML. Tetapi di C++/WinRT, semua entitas yang digunakan dengan menggunakan ekstensi markup XAML {x:Bind} harus diekspos secara publik di IDL.

Selain itu, mengikat boolean ditampilkan true atau di C#, tetapi menampilkan Windows.Foundation.IReference'1<Boolean> di C++/WinRTfalse.

Untuk informasi selengkapnya, dan contoh kode, lihat Menggunakan objek dari markup.

Membuat sumber data tersedia untuk markup XAML

Di C++/WinRT versi 2.0.190530.8 atau yang lebih baru, winrt::single_threaded_observable_vector membuat vektor yang dapat diamati yang mendukung IObservableVector<T> dan IObservableVector<IInspectable>. Misalnya, lihat Porting properti Skenario.

Anda dapat menulis file Midl Anda (.idl) seperti ini (juga lihat Memperhitungkan kelas runtime ke dalam file Midl (.idl)).

namespace Bookstore
{
    runtimeclass BookSku { ... }

    runtimeclass BookstoreViewModel
    {
        Windows.Foundation.Collections.IObservableVector<BookSku> BookSkus{ get; };
    }

    runtimeclass MainPage : Windows.UI.Xaml.Controls.Page
    {
        MainPage();
        BookstoreViewModel MainViewModel{ get; };
    }
}

Dan mengimplementasikan seperti ini.

// BookstoreViewModel.h
...
struct BookstoreViewModel : BookstoreViewModelT<BookstoreViewModel>
{
    BookstoreViewModel()
    {
        m_bookSkus = winrt::single_threaded_observable_vector<Bookstore::BookSku>();
        m_bookSkus.Append(winrt::make<Bookstore::implementation::BookSku>(L"To Kill A Mockingbird"));
    }
    
	Windows::Foundation::Collections::IObservableVector<Bookstore::BookSku> BookSkus();
    {
        return m_bookSkus;
    }

private:
    Windows::Foundation::Collections::IObservableVector<Bookstore::BookSku> m_bookSkus;
};
...

Untuk informasi selengkapnya, lihat Kontrol item XAML; ikat ke koleksi C++/WinRT, dan Koleksi dengan C++/WinRT.

Membuat sumber data tersedia untuk markup XAML (sebelum C++/WinRT 2.0.190530.8)

Pengikatan data XAML mengharuskan sumber item mengimplementasikan IInspectable IIterable><, serta salah satu kombinasi antarmuka berikut.

  • IObservableVector<IInspectable>
  • IBindableVector dan INotifyCollectionChanged
  • IBindableVector dan IBindableObservableVector
  • IBindableVector dengan sendirinya (tidak akan merespons perubahan)
  • IVector<IInspectable>
  • IBindableIterable (akan mengulang dan menyimpan elemen ke dalam koleksi privat)

Antarmuka generik seperti IVector<T> tidak dapat dideteksi saat runtime. Setiap IVector<T> memiliki pengidentifikasi antarmuka (IID) yang berbeda, yang merupakan fungsi T. Setiap pengembang dapat memperluas set T secara sembrono, jadi dengan jelas kode pengikatan XAML tidak pernah dapat mengetahui set lengkap untuk kueri. Pembatasan itu bukan masalah untuk C# karena setiap objek CLR yang mengimplementasikan IEnumerable<T> secara otomatis menerapkan IEnumerable. Pada tingkat ABI, itu berarti bahwa setiap objek yang mengimplementasikan IObservableVector<T> secara otomatis mengimplementasikan IObservableVector<IInspectable>.

C++/WinRT tidak menawarkan jaminan tersebut. Jika kelas runtime C++/WinRT mengimplementasikan IObservableVector<T>, maka kami tidak dapat berasumsi bahwa implementasi IObservableVector<IInspectable> juga disediakan.

Akibatnya, berikut adalah bagaimana contoh sebelumnya perlu terlihat.

...
runtimeclass BookstoreViewModel
{
    // This is really an observable vector of BookSku.
    Windows.Foundation.Collections.IObservableVector<Object> BookSkus{ get; };
}

Dan implementasinya.

// BookstoreViewModel.h
...
struct BookstoreViewModel : BookstoreViewModelT<BookstoreViewModel>
{
    BookstoreViewModel()
    {
        m_bookSkus = winrt::single_threaded_observable_vector<Windows::Foundation::IInspectable>();
        m_bookSkus.Append(winrt::make<Bookstore::implementation::BookSku>(L"To Kill A Mockingbird"));
    }
    
    // This is really an observable vector of BookSku.
	Windows::Foundation::Collections::IObservableVector<Windows::Foundation::IInspectable> BookSkus();
    {
        return m_bookSkus;
    }

private:
    Windows::Foundation::Collections::IObservableVector<Windows::Foundation::IInspectable> m_bookSkus;
};
...

Jika anda perlu mengakses objek di m_bookSkus, maka anda harus QI mereka kembali ke Bookstore::BookSku.

Widget MyPage::BookstoreViewModel(winrt::hstring title)
{
    for (auto&& obj : m_bookSkus)
    {
        auto bookSku = obj.as<Bookstore::BookSku>();
        if (bookSku.Title() == title) return bookSku;
    }
    return nullptr;
}

Kelas turunan

Untuk memperoleh dari kelas runtime, kelas dasar harus dapat disusupi. C# tidak mengharuskan Anda mengambil langkah khusus untuk membuat kelas Anda dapat disusupi, tetapi C++/WinRT tidak. Anda menggunakan kata kunci yang tidak disegel untuk menunjukkan bahwa Anda ingin kelas Anda dapat digunakan sebagai kelas dasar.

unsealed runtimeclass BasePage : Windows.UI.Xaml.Controls.Page
{
    ...
}
runtimeclass DerivedPage : BasePage
{
    ...
}

Dalam file header untuk jenis implementasi, Anda harus menyertakan file header kelas dasar sebelum menyertakan header yang dibuat secara otomatis untuk kelas turunan. Jika tidak, Anda akan mendapatkan kesalahan seperti "Penggunaan ilegal dari jenis ini sebagai ekspresi".

// DerivedPage.h
#include "BasePage.h"       // This comes first.
#include "DerivedPage.g.h"  // Otherwise this header file will produce an error.

namespace winrt::MyNamespace::implementation
{
    struct DerivedPage : DerivedPageT<DerivedPage>
    {
        ...
    }
}

API penting