Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
Návod
Pokud jste si toto téma přečetli dříve a vracíte se k němu s ohledem na konkrétní úkol, můžete přejít na Najít obsah na základě úkolu, který provádíte části tohoto tématu.
Toto téma komplexně katalogizuje technické podrobnosti týkající se přenosu zdrojového kódu z projektu C# do jeho ekvivalentu v C++/WinRT.
Případovou studii přenesení jedné z ukázek aplikací pro Univerzální platformu Windows (UPW) najdete v doprovodném tématu přenesení ukázky aplikace Schránka do C++/WinRT z C#. Můžete získat praktické dovednosti a zkušenosti s přenosem pomocí tohoto průvodce tím, že si sami přenesete tuto ukázku, jak budete postupovat.
Jak se připravit a co očekávat
Případová studie přenesení ukázky schránky do C++/WinRT z C# ukazuje příklady typů rozhodnutí o návrhu softwaru, která provedete při přenosu projektu do C++/WinRT. Proto je vhodné se připravit na přenos tím, že získáte solidní znalosti o tom, jak stávající kód funguje. Tímto způsobem získáte dobrý přehled o funkcích aplikace, struktuře kódu, a rozhodnutí, která provedete, vás vždy povedou dál, a to správným směrem.
Z hlediska toho, jaké druhy změn přenosu se mají očekávat, můžete je seskupit do čtyř kategorií.
-
Portujte projekci jazyka. Prostředí Windows Runtime (WinRT) je projektované do různých programovacích jazyků. Každá z těchto jazykových projekcí je navržena tak, aby působila idiomaticky v daném programovacím jazyce. V jazyce C# se některé typy prostředí Windows Runtime promítají jako typy .NET. Například budete překládat System.Collections.Generic.IReadOnlyList<T> zpět na Windows.Foundation.Collections.IVectorView<T>. V jazyce C# jsou některé operace prostředí Windows Runtime promítnuty jako pohodlné jazykové funkce jazyka C#. Příkladem je, že v jazyce C# použijete syntaxi operátoru
+=k registraci delegáta zpracování událostí. Budete tedy překládat jazykové funkce, jako je například tato, zpět na základní operaci, která se provádí (v tomto příkladu registrace události). -
syntaxe portového jazyka. Mnoho z těchto změn je jednoduchých mechanických transformací, nahrazení jednoho symbolu za druhý. Například změna tečky (
.) na dvojtečku (::). -
procedura jazyka portu. Některé z nich mohou být jednoduché, opakující se změny (například
myObject.MyPropertynamyObject.MyProperty()). Jiní potřebují hlubší změny (například portování procedury, která zahrnuje použití System.Text.StringBuilder na takový, který zahrnuje použití std::wostringstream). -
úlohy související s portováním, které jsou specifické pro C++/WinRT. Některé podrobnosti prostředí Windows Runtime se na pozadí starají implicitně pomocí jazyka C#. Tyto podrobnosti se provádějí explicitně v jazyce C++/WinRT. Příkladem je, že k definování tříd modulu runtime použijete soubor
.idl.
Po následujícím indexu založeném na úlohách jsou zbývající části tohoto tématu strukturovány podle výše uvedené taxonomie.
Vyhledání obsahu na základě úkolu, který provádíte
| Úkol | Obsah |
|---|---|
| Navrhněte komponentu Windows Runtime (WRC) | Určitou funkcionalitu je možné dosáhnout (nebo určitá API volat) pouze v jazyce C++. Tuto funkci můžete zohlednit v jazyce C++/WinRT WRC a pak využívat WRC z aplikace jazyka C# (například). Viz komponenty Windows Runtime s C++/WinRT a pokud vytváříte běhovou třídu v komponentě prostředí Windows Runtime. |
| Přenést asynchronní metodu | Je dobrý nápad, aby první řádek asynchronní metody v runtime třídě C++/WinRT byl auto lifetime = get_strong(); (viz Bezpečný přístup k ukazateli this v korutině člena třídy).Přenos z Task, viz Asynchronní akce.Přenos z Task<T>, viz asynchronní operace.Přenesení z async void, viz metodu "Odpálit a zapomenout" . |
| Přenést třídu | Nejprve určete, zda třída musí být třídou modulu runtime, nebo zda může být běžnou třídou. Abyste se mohli rozhodnout, podívejte se na úplně začátek rozhraní API pro vytváření pomocíC++/WinRT . Pak se podívejte na následující tři řádky. |
| Port třídy modulu runtime | Třída, která sdílí funkce mimo aplikaci C++ nebo třídu, která se používá v datové vazbě XAML. Přečtěte si , pokud vytváříte runtime třídu v rámci komponenty Windows Runtime, nebo , pokud vytváříte runtime třídu, na kterou se má odkazovat ve vašem uživatelském rozhraní XAML. Tyto odkazy tento popis podrobněji popisují, ale třída modulu runtime musí být deklarována v IDL. Pokud projekt již obsahuje soubor IDL (například Project.idl), doporučujeme deklarovat všechny nové třídy modulu runtime v tomto souboru. V IDL deklarujte všechny metody a datové členy, které se použijí mimo vaši aplikaci nebo které se použijí v XAML. Po aktualizaci souboru IDL znovu sestavte a prohlédněte vygenerované soubory zástupných procedur (.h a .cpp) ve složce Generated Files projektu (v Průzkumníku řešení, s vybraným uzlem projektu se ujistěte, že je zapnutá možnost Zobrazit všechny soubory). Porovnejte soubory zástupných procedur se soubory, které už jsou ve vašem projektu, a podle potřeby přidejte soubory nebo přidejte či aktualizujte definice funkcí. Syntaxe zástupných souborů je vždy správná, proto doporučujeme její použití, abyste minimalizovali chyby při sestavení. Jakmile zástupné kódy ve vašem projektu odpovídají souborům s zástupnými kódy, můžete pokračovat a implementovat je převodem kódu C#. |
| Přenos běžné třídy | Podívejte se na pokud nepíšete třídu modulu runtime. |
| Autor IDL |
Úvod do jazyka Microsoft Interface Definition Language 3.0 Pokud vytvoříte třídu modulu runtime, na kterou se odkazuje v uživatelském rozhraní XAML Využívání objektů ze zápisu XAML Definování tříd modulu runtime v IDL |
| Přeneste kolekci | kolekce s C++/WinRT Zpřístupnění zdroje dat pro značkování XAML Asociativní kontejner přístup k členu vektoru |
| Přenést událost |
delegát obslužné rutiny události jako člen třídy odvolání delegáta obsluhy události |
| Port metody | Z jazyka C#: private async void SampleButton_Tapped(object sender, Windows.UI.Xaml.Input.TappedRoutedEventArgs e) { ... }Do souboru C++/WinRT .h: fire_and_forget SampleButton_Tapped(IInspectable const&, RoutedEventArgs const&);Do souboru C++/WinRT .cpp: fire_and_forget OcrFileImage::SampleButton_Tapped(IInspectable const&, RoutedEventArgs const&) {...} |
| Řetězce portů |
Zpracování řetězců v C++/WinRT toString Sestavování řetězců Boxing a rozbalení řetězce |
| Převod typu (přetypování typu) | C#: o.ToString()C++/WinRT: to_hstring(static_cast<int>(o))Viz také ToString. C#: (Value)oC++/WinRT: unbox_value<Value>(o)Vyvolá se v případě, že se nepovede rozbalení. Viz také Boxing a unboxing. C#: o as Value? ?? fallbackC++/WinRT: unbox_value_or<Value>(o, fallback)Vrátí náhradní hodnotu, pokud se nepovede rozbalení. Viz také Boxing a unboxing. C#: (Class)oC++/WinRT: o.as<Class>()Vyvolá chybu v případě selhání převodu. C#: o as ClassC++/WinRT: o.try_as<Class>()Vrátí hodnotu null, pokud se převod nezdaří. |
Změny, které zahrnují projekci jazyka
| Kategorie | C# | C++/WinRT | Viz také |
|---|---|---|---|
| Netypovaný objekt |
objectnebo System.Object |
Windows::Foundation::IInspectable | Převod metody EnableClipboardContentChangedNotifications |
| Obory názvů projekce | using System; |
using namespace Windows::Foundation; |
|
using System.Collections.Generic; |
using namespace Windows::Foundation::Collections; |
||
| Velikost kolekce | collection.Count |
collection.Size() |
Přenesení metody BuildClipboardFormatsOutputString |
| Typický typ kolekce | IList<T>a Přidat přidat prvek. | IVector<T>a Append pro přidání prvku. Pokud někde používáte std::vector, použijte push_back k přidání prvku. | |
| Typ kolekce jen pro čtení | IReadOnlyList<T> | IVectorView<T> | Přenesení metody BuildClipboardFormatsOutputString |
| delegát obsluhy události jako člen třídy | myObject.EventName += Handler; |
token = myObject.EventName({ get_weak(), &Class::Handler }); |
Převod metody EnableClipboardContentChangedNotifications |
| Odvolání delegáta obslužné rutiny události | myObject.EventName -= Handler; |
myObject.EventName(token); |
Převod metody EnableClipboardContentChangedNotifications |
| asociativní kontejner | IDictionary<K, V> | IMap<K, V> | |
| přístup člena vektoru | x = v[i];v[i] = x; |
x = v.GetAt(i);v.SetAt(i, x); |
Registrace nebo odvolání obslužné rutiny události
V jazyce C++/WinRT máte několik syntaktických možností pro registraci/odvolání obslužného delegáta události, jak je popsáno v tématu Zpracování událostí pomocí delegátů v C++/WinRT. Viz také přenos metody EnableClipboardContentChangedNotifications.
Někdy se například stane, že příjemce události (objekt zpracovávající událost) má být zničen, a proto budete chtít odvolat obslužnou funkci události, aby zdroj události (objekt vyvolávající událost) nevolal na zničený objekt. Viz Odvolání registrovaného delegáta. V takových případech vytvořte event_token členské proměnné pro obslužné rutiny událostí. Viz příklad v Portingu metody EnableClipboardContentChangedNotifications.
Obslužnou rutinu události můžete také zaregistrovat v kódu XAML.
<Button x:Name="OpenButton" Click="OpenButton_Click" />
V jazyce C# může být vaše metoda OpenButton_Click privátní a XAML ji stále bude moct připojit k události ButtonBase.Click vyvolané tlačítkem OpenButton.
V jazyce C++/WinRT musí být vaše metoda OpenButton_Click veřejná ve vašem typu implementace, pokud ji chcete zaregistrovat v kódu XAML. Pokud zaregistrujete obslužnou rutinu události pouze v imperativním kódu, obslužná rutina události nemusí být veřejná.
namespace winrt::MyProject::implementation
{
struct MyPage : MyPageT<MyPage>
{
void OpenButton_Click(
winrt::Windows:Foundation::IInspectable const& sender,
winrt::Windows::UI::Xaml::RoutedEventArgs const& args);
}
};
Alternativně můžete z XAML stránky udělat "přítele" vašeho implementačního typu a OpenButton_Click nastavit jako soukromý.
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);
}
};
Jedním z konečných scénářů je situace, kdy projekt C#, který portujete , vytvoří vazbu na obslužnou rutinu události z kódu (další pozadí tohoto scénáře najdete v tématu Functions v x:Bind).
<Button x:Name="OpenButton" Click="{x:Bind OpenButton_Click}" />
Stačí změnit tento kód na jednodušší Click="OpenButton_Click". Nebo pokud chcete, můžete tuto značku zachovat tak, jak je. Vše, co musíte udělat pro podporu, je deklarovat obslužnou rutinu události v IDL.
void OpenButton_Click(Object sender, Windows.UI.Xaml.RoutedEventArgs e);
Poznámka:
Deklarujte funkci jako void i v případě, že implementujete jako Fire a zapomenete.
Změny, které zahrnují syntaxi jazyka
| Kategorie | C# | C++/WinRT | Viz také |
|---|---|---|---|
| Modifikátory přístupu | public \<member\> |
public:\<member\> |
portování metody Button_Click |
| Přístup k datovému členu | this.variable |
this->variable |
|
| asynchronní akce | async Task ... |
IAsyncAction ... |
rozhraní IAsyncAction, souběžnost a asynchronní operace s C++/WinRT |
| asynchronní operace | async Task<T> ... |
IAsyncOperation<T> ... |
rozhraní IAsyncOperation, souběžnost a asynchronní operace s C++/WinRT |
| metoda Fire-and-forget (znamená, že je asynchronní) | async void ... |
winrt::fire_and_forget ... |
Přenášení metody CopyButton_Click, Nastřel a zapomeň |
| Přístup k výčtové konstantě | E.Value |
E::Value |
Přenesení metody DisplayChangedFormats |
| Kooperativní čekání | await ... |
co_await ... |
portování metody CopyButton_Click |
| Kolekce projektovaných typů jako privátní pole | private List<MyRuntimeClass> myRuntimeClasses = new List<MyRuntimeClass>(); |
std::vector<MyNamespace::MyRuntimeClass>m_myRuntimeClasses; |
|
| Konstrukce 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} }; |
|
| Oddělovač oboru názvů | A.B.T |
A::B::T |
|
| Nula | null |
nullptr |
Přenesení metody UpdateStatus |
| Získání objektu typu | typeof(MyType) |
winrt::xaml_typename<MyType>() |
portování vlastností Scénáře |
| Deklarace parametru pro metodu | MyType |
MyType const& |
předávání parametrů |
| Deklarace parametru pro asynchronní metodu | MyType |
MyType |
předávání parametrů |
| Volání statické metody | T.Method() |
T::Method() |
|
| Řetězce |
stringnebo System.String |
winrt::hstring | Zpracování řetězců v C++/WinRT |
| Řetězcový literál | "a string literal" |
L"a string literal" |
portování konstruktoru, Aktuálnía FEATURE_NAME |
| Odvozený (nebo vyvolaný) typ | var |
auto |
Přenesení metody BuildClipboardFormatsOutputString |
| Direktiva používání | using A.B.C; |
using namespace A::B::C; |
portování konstruktoru, Aktuálnía FEATURE_NAME |
| Doslovný/surový řetězcový literál | @"verbatim string literal" |
LR"(raw string literal)" |
portování metody DisplayToast |
Poznámka:
Pokud hlavičkový soubor neobsahuje direktivu using namespace pro daný obor názvů, budete muset plně kvalifikovat všechny názvy typů pro tento obor názvů; nebo je alespoň dostatečně kvalifikovat, aby je kompilátor našel. Příklad najdete v tématu Portování metody DisplayToast.
Přenos tříd a členů
Pro každý typ jazyka C# budete muset rozhodnout, jestli se má portovat do typu prostředí Windows Runtime, nebo do běžné třídy,struktury/výčtu jazyka C++. Další informace a podrobné příklady ilustrující, jak tato rozhodnutí provést, najdete v tématu portování ukázky schránky do C++/WinRT z C#.
Vlastnost jazyka C# se obvykle stává přistupující funkcí, funkcí mutátoru a záložním datovým členem. Další informace a příklad najdete v tématu Přenesení vlastnosti IsClipboardContentChangedEnabled.
U nestatického pole je nastavte jako datové členy typu implementace.
Statické pole jazyka C# se stane přistupovací a/nebo mutátorovou funkcí jazyka C++/WinRT. Další informace a příklad najdete v tématu Portování konstruktoru, Aktuálnía FEATURE_NAME.
U členských funkcí budete muset znovu rozhodnout, jestli patří do IDL, nebo jestli se jedná o veřejnou nebo soukromou členskou funkci vašeho typu implementace. Pro více informací a příklady, jak se rozhodnout, si prohlédněte IDL pro MainPage typ.
Přenos značek XAML a souborů prostředků
V případě portování ukázky schránky do C++/WinRT zjazyka C# jsme mohli použít stejných kódu XAML (včetně prostředků) a souborů prostředků v jazyce C# a projektu C++/WinRT. V některých případech budou úpravy značek nutné, aby toho bylo dosaženo. Podívejte se na Zkopírujte XAML a styly potřebné k dokončení portování MainPage.
Změny, které zahrnují postupy v rámci jazyka
| Kategorie | C# | C++/WinRT | Viz také |
|---|---|---|---|
| Správa doby života v asynchronní metodě | není k dispozici |
auto lifetime{ get_strong() }; neboauto lifetime = get_strong(); |
portování metody CopyButton_Click |
| Likvidace | using (var t = v) |
auto t{ v };t.Close(); // or let wrapper destructor do the work |
|
| Vytvořit objekt | new MyType(args) |
MyType{ args } neboMyType(args) |
portování vlastností Scénáře |
| Vytvoření neinicializovaného odkazu | MyType myObject; |
MyType myObject{ nullptr }; neboMyType myObject = nullptr; |
portování konstruktoru, Aktuálnía FEATURE_NAME |
| Vytvoření objektu do proměnné pomocí args | var myObject = new MyType(args); |
auto myObject{ MyType{ args } }; nebo auto myObject{ MyType(args) }; nebo auto myObject = MyType{ args }; nebo auto myObject = MyType(args); nebo MyType myObject{ args }; nebo MyType myObject(args); |
portování metody Footer_Click |
| Vytvoření objektu do proměnné bez args | var myObject = new T(); |
MyType myObject; |
Přenesení metody BuildClipboardFormatsOutputString |
| Zkratka inicializace objektu | var p = new FileOpenPicker{ViewMode = PickerViewMode.List}; |
FileOpenPicker p;p.ViewMode(PickerViewMode::List); |
|
| Hromadná vektorová operace | var p = new FileOpenPicker{FileTypeFilter = { ".png", ".jpg", ".gif" }}; |
FileOpenPicker p;p.FileTypeFilter().ReplaceAll({ L".png", L".jpg", L".gif" }); |
portování metody CopyButton_Click |
| Procházet kolekci | foreach (var v in c) |
for (auto&& v : c) |
Přenesení metody BuildClipboardFormatsOutputString |
| Zachycení výjimky | catch (Exception ex) |
catch (winrt::hresult_error const& ex) |
portování metody PasteButton_Click |
| Podrobnosti o výjimce | ex.Message |
ex.message() |
portování metody PasteButton_Click |
| Získání hodnoty vlastnosti | myObject.MyProperty |
myObject.MyProperty() |
Přenášení metody NotifyUser |
| Nastavení hodnoty vlastnosti | myObject.MyProperty = value; |
myObject.MyProperty(value); |
|
| Zvýšení hodnoty vlastnosti | myObject.MyProperty += v; |
myObject.MyProperty(thing.Property() + v);U řetězců přepněte na tvůrce. |
|
| ToString() | myObject.ToString() |
winrt::to_hstring(myObject) |
ToString() |
| Převod jazykového řetězce na řetězec Windows Runtime | není k dispozici | winrt::hstring{ s } |
|
| Vytváření řetězců | StringBuilder builder;builder.Append(...); |
std::wostringstream builder;builder << ...; |
Sestavování řetězců |
| Interpolace řetězců | $"{i++}) {s.Title}" |
winrt::to_hstringa/nebo winrt::hstring::operator+ | Přenesení metody OnNavigatedTo |
| Prázdný řetězec pro porovnání | System.String.Empty | winrt::hstring::empty | Přenesení metody UpdateStatus |
| Vytvoř prázdný řetězec | var myEmptyString = String.Empty; |
winrt::hstring myEmptyString{ L"" }; |
|
| Operace slovníku | map[k] = v; // replaces any existingv = map[k]; // throws if not presentmap.ContainsKey(k) |
map.Insert(k, v); // replaces any existingv = map.Lookup(k); // throws if not presentmap.HasKey(k) |
|
| Převod typu (vyvolání při selhání) | (MyType)v |
v.as<MyType>() |
portování metody Footer_Click |
| Převod typu (pokud dojde k selhání, vrátí null) | v as MyType |
v.try_as<MyType>() |
portování metody PasteButton_Click |
| Elementy XAML s x:Name jsou vlastnosti | MyNamedElement |
MyNamedElement() |
portování konstruktoru, Aktuálnía FEATURE_NAME |
| Přepnutí na vlákno uživatelského rozhraní | CoreDispatcher.RunAsync | CoreDispatcher.RunAsyncnebo winrt::resume_foreground | Portování metody NotifyUsera Portování metody HistoryAndRoaming |
| Konstrukce elementu uživatelského rozhraní v imperativním kódu na stránce XAML | Viz konstrukce prvků uživatelského rozhraní |
Viz konstrukce prvků uživatelského rozhraní |
Následující části obsahují podrobnější informace o některých položkách v tabulce.
Konstrukce prvků uživatelského rozhraní
Tyto příklady kódu ukazují vytvoření prvku uživatelského rozhraní v imperativním kódu stránky 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()
Typy jazyka C# poskytují metodu Object.ToString.
int i = 2;
var s = i.ToString(); // s is a System.String with value "2".
C++/WinRT přímo neposkytuje toto zařízení, ale můžete se obrátit na alternativy.
int i{ 2 };
auto s{ std::to_wstring(i) }; // s is a std::wstring with value L"2".
C++/WinRT také podporuje winrt::to_hstring pro omezený počet typů. Budete muset přidat přetížení pro všechny další typy, které chcete převést na řetězec.
| Jazyk | Převeď int na řetězec | Stringifikace výčtového typu |
|---|---|---|
| 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); |
V případě převedení výčtu na řetězec budete muset poskytnout implementaci 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));
}
}
}
Tyto znázornění řetězců jsou často implicitně zpracovávány datovými vazbami.
<TextBlock>
You have <Run Text="{Binding FlowerCount}"/> flowers.
</TextBlock>
<TextBlock>
Most recent status is <Run Text="{x:Bind LatestOperation.Status}"/>.
</TextBlock>
Tyto vazby budou provádět winrt::to_hstring vázané vlastnosti. V případě druhého příkladu (StatusEnum) musíte zadat vlastní přetížení winrt::to_hstring, jinak se zobrazí chyba kompilátoru.
Viz také Portování metody Footer_Click.
Vytváření řetězců
Pro vytváření řetězců má jazyk C# integrovaný typ StringBuilder.
| Kategorie | C# | C++/WinRT |
|---|---|---|
| Vytváření řetězců | StringBuilder builder;builder.Append(...); |
std::wostringstream builder;builder << ...; |
| Připojit řetězec Windows Runtime se zachováním nulových hodnot | builder.Append(s); |
builder << std::wstring_view{ s }; |
| Přidání nového řádek | builder.Append(Environment.NewLine); |
builder << std::endl; |
| Přístup k výsledku | s = builder.ToString(); |
ws = builder.str(); |
Viz také portování BuildClipboardFormatsOutputString metodaa Porting DisplayChangedFormats metoda.
Spouštění kódu na hlavním vlákně uživatelského rozhraní
Tento příklad je převzat ze vzorku skeneru čárových kódů .
Pokud chcete pracovat na hlavním vlákně uživatelského rozhraní v projektu C#, obvykle používáte metodu CoreDispatcher.RunAsync, jako je tato.
private async void Watcher_Added(DeviceWatcher sender, DeviceInformation args)
{
await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
// Do work on the main UI thread here.
});
}
V jazyce C++/WinRT je mnohem jednodušší to vyjádřit. Všimněte si, že přijímáme parametry podle hodnoty na předpokladu, že k nim budeme chtít přistupovat po prvním bodu pozastavení (v tomto případě co_await). Další informace najdete v tématu předávání parametrů.
winrt::fire_and_forget Watcher_Added(DeviceWatcher sender, winrt::DeviceInformation args)
{
co_await Dispatcher();
// Do work on the main UI thread here.
}
Pokud potřebujete provádět práci s jinou prioritou než výchozí, podívejte se na funkci winrt::resume_foreground, která má přetížení, které přijímá prioritu. Příklady kódu ukazující, jak čekat na volání winrt::resume_foreground, naleznete v části Programování se zaměřením na spřažení vláken.
Přenos úloh souvisejících s C++/WinRT
Definování tříd modulu runtime v IDL
Viz IDL pro MainPage typa konsolidaci vašich souborů .idl.
Zahrňte soubory hlaviček oboru názvů C++/WinRT pro Windows, které potřebujete.
V jazyce C++/WinRT musíte vždy, když chcete použít typ z oborů názvů Systému Windows, zahrnout odpovídající soubor hlaviček oboru názvů C++/WinRT systému Windows. Příklad najdete v tématu Porting metody NotifyUser.
Boxování a rozbalování
Jazyk C# automaticky rozdělí skaláry do objektů. C++/WinRT vyžaduje, abyste explicitně volali funkci winrt::box_value. Oba jazyky vyžadují explicitní rozbalení. Vizte boxování a unboxování s C++/WinRT.
V následujících tabulkách použijeme tyto definice.
| C# | C++/WinRT |
|---|---|
int i; |
int i; |
string s; |
winrt::hstring s; |
object o; |
IInspectable o; |
| Operace | C# | C++/WinRT |
|---|---|---|
| Boxování | o = 1;o = "string"; |
o = box_value(1);o = box_value(L"string"); |
| Rozbalení | i = (int)o;s = (string)o; |
i = unbox_value<int>(o);s = unbox_value<winrt::hstring>(o); |
C++/CX a C# vyvolá výjimky, pokud se pokusíte rozbalit ukazatel null na typ hodnoty. C++/WinRT to považuje za programátorskou chybu a zhroutí se. V jazyce C++/WinRT použijte funkci winrt::unbox_value_or, pokud chcete zpracovat případ, kdy objekt není typu, o kterém jste si mysleli, že je.
| Scénář | C# | C++/WinRT |
|---|---|---|
| Rozbalte známé celé číslo | i = (int)o; |
i = unbox_value<int>(o); |
| Pokud má o hodnotu null | System.NullReferenceException |
Havárie |
| Pokud o není objektový int | System.InvalidCastException |
Havárie |
| Rozbalit int, použít záložní možnost, pokud je hodnota null; ukončit aplikaci, pokud je to něco jiného. | i = o != null ? (int)o : fallback; |
i = o ? unbox_value<int>(o) : fallback; |
| Pokud je to možné, rozbalte int; použijte náhradní možnost pro cokoli jiného | i = as int? ?? fallback; |
i = unbox_value_or<int>(o, fallback); |
Příklad najdete v tématu Portování metody OnNavigatedToa Portování metody Footer_Click.
Zabalování a rozbalování řetězce
Řetězec je nějakým způsobem typ hodnoty a jiným způsobem typ odkazu. C# a C++/WinRT zachází s řetězci odlišně.
Typ ABI HSTRING je ukazatel na řetězec s počítáním referencí. Ale neodvozuje se z IInspectable, takže technicky to není objekt. Kromě toho nulový HSTRING představuje prázdný řetězec. Zabalení objektů, které nejsou odvozeny z IInspectable, se provádí jejich vložením do IReference<T>. Windows Runtime poskytuje standardní implementaci ve formě objektu PropertyValue (vlastní typy se hlásí jako PropertyType::OtherType).
Jazyk C# představuje řetězec prostředí Windows Runtime jako typ odkazu; zatímco C++/WinRT projektuje řetězec jako typ hodnoty. To znamená, že obalený nulový řetězec může mít různé reprezentace v závislosti na tom, jak jste se k němu dostali.
| Chování | C# | C++/WinRT |
|---|---|---|
| Prohlášení | object o;string s; |
IInspectable o;hstring s; |
| Kategorie typu řetězce | Typ odkazu | Typ hodnoty |
| null jako HSTRING projekty | "" |
hstring{} |
Jsou hodnoty null a "" stejné? |
Ne | Ano |
| Platnost hodnoty null | s = null;s.Length vyvolá nullReferenceException |
s = hstring{};s.size() == 0 (platné) |
| Pokud k objektu přiřadíte řetězec s hodnotou null. | o = (string)null;o == null |
o = box_value(hstring{});o != nullptr |
Pokud přiřadíte "" k objektu |
o = "";o != null |
o = box_value(hstring{L""});o != nullptr |
Základní boxování a rozbalení.
| Operace | C# | C++/WinRT |
|---|---|---|
| Zabalit řetězec do krabice | o = s;Prázdný řetězec se stane objektem, který není null. |
o = box_value(s);Prázdný řetězec se stane objektem, který není null. |
| Rozbalení známého řetězce | s = (string)o;Objekt Null se stane řetězcem null. InvalidCastException, pokud není řetězec. |
s = unbox_value<hstring>(o);Pád způsobený objektem null. Selže, pokud není řetězec. |
| Rozbalení možného řetězce | s = o as string;Objekt null nebo ne-řetězec se změní na řetězec null. NEBO s = o as string ?? fallback;Null nebo jiná než textová hodnota se změní na záložní hodnotu. Prázdný řetězec se zachová. |
s = unbox_value_or<hstring>(o, fallback);Null nebo jiná než textová hodnota se změní na záložní hodnotu. Prázdný řetězec se zachová. |
Zpřístupnění třídy pro rozšíření {Binding} v značkovacím jazyce
Pokud máte v úmyslu použít rozšíření značek {Binding} k datové vazbě k datovému typu, podívejte se na objekt vazby deklarovaný pomocí {Binding}.
Využívání objektů z XAML značek
V projektu jazyka C# můžete využívat soukromé členy a pojmenované elementy z kódu XAML. V jazyce C++/WinRT musí být ale všechny entity používané pomocí rozšíření XAML {x:Bind} veřejně zpřístupněny v IDL.
Vazba na booleovskou hodnotu také zobrazuje true nebo false v jazyce C#, ale zobrazuje Windows.Foundation.IReference`1<booleovská hodnota> v jazyce C++/WinRT.
Další informace a příklady kódu viz Využívání objektů z markupu.
Zpřístupnění zdroje dat pro kód XAML
V C++/WinRT ve verzi 2.0.190530.8 nebo novější winrt::single_threaded_observable_vector vytvoří vektor, který je pozorovatelný a podporuje jak IObservableVector<T>, tak IObservableVector<IInspectable>. Jako příklad viz vlastnost Porting Scénáře.
Soubor Midl (.idl) můžete vytvořit takto (viz také třídy modulu runtime Factoring do souborů 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; };
}
}
A implementujte takhle.
// 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;
};
...
Další informace najdete v tématu ovládací prvky položek XAML; připojení ke kolekci C++/WinRTa Kolekce s C++/WinRT.
Zpřístupnění zdroje dat pro kód XAML (před C++/WinRT 2.0.190530.8)
Vazba dat XAML vyžaduje, aby zdroj položek implementuje IIterable<IInspectable>, stejně jako jednu z následujících kombinací rozhraní.
- IObservableVector<IInspectable>
- IBindableVector a INotifyCollectionChanged
- IBindableVector a IBindableObservableVector
- IBindableVector sám (nebude reagovat na změny)
- IVector<IInspectable>
- IBindableIterable (bude iterovat a ukládat prvky do soukromé kolekce)
Obecné rozhraní, jako je IVector<T>, nelze zjistit za běhu. Každý IVector<T> má jiný identifikátor rozhraní (IID), což je funkce T. Každý vývojář může libovolně rozšířit sadu T, takže jasně, že kód vazby XAML nikdy nezná úplnou sadu pro dotazování. Toto omezení není problém pro jazyk C#, protože každý objekt CLR implementuje IEnumerable<T> automaticky implementuje IEnumerable. Na úrovni ABI to znamená, že každý objekt, který implementuje IObservableVector<T> automaticky implementuje IObservableVector<IInspectable>.
C++/WinRT nenabízí tuto záruku. Pokud třída modulu runtime C++/WinRT implementuje IObservableVector<T>, pak nemůžeme předpokládat, že implementace IObservableVector<IInspectable> je také nějakým způsobem k dispozici.
Takto by měl vypadat předchozí příklad.
...
runtimeclass BookstoreViewModel
{
// This is really an observable vector of BookSku.
Windows.Foundation.Collections.IObservableVector<Object> BookSkus{ get; };
}
Implementace.
// 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;
};
...
Pokud potřebujete přistupovat k objektům v m_bookSkus, budete je muset QI vrátit zpět do 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;
}
Odvozené třídy
Aby bylo možné odvodit běhovou třídu, musí být základní třída kompozitelná. Jazyk C# nevyžaduje provedení žádných speciálních kroků, aby vaše třídy byly kompozibilní, ale C++/WinRT to vyžaduje. Pomocí nezapečetěného klíčového slova označíte, že chcete, aby vaše třída byla použitelná jako základní třída.
unsealed runtimeclass BasePage : Windows.UI.Xaml.Controls.Page
{
...
}
runtimeclass DerivedPage : BasePage
{
...
}
Do souboru hlaviček typu implementacemusíte zahrnout soubor hlaviček základní třídy před zahrnutím automaticky generované hlavičky pro odvozenou třídu. V opačném případě se zobrazí chyby typu Neplatné použití tohoto typu jako výrazu.
// 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>
{
...
}
}
Důležitá rozhraní API
Související témata
- návody C#
- C++/WinRT
- Datová vazba do hloubky