Notitie
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen u aan te melden of de directory te wijzigen.
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen de mappen te wijzigen.
Aanbeveling
Als u dit onderwerp eerder hebt gelezen en u teruggaat naar het onderwerp met een bepaalde taak in gedachten, kunt u naar de Inhoud zoeken gaan op basis van de taak die u uitvoert sectie van dit onderwerp.
In dit onderwerp worden de technische details die betrokken zijn bij het overzetten van de broncode in een C# project uitgebreid beschreven naar een equivalent in C++/WinRT.
Voor een casestudy over het porteren van een van de Universal Windows Platform (UWP) app-voorbeelden, zie het bijbehorende onderwerp Porting the Clipboard sample to C++/WinRT from C#. U kunt porteren oefenen en ervaring opdoen door de stapsgewijze handleiding te volgen en het voorbeeld zelf te porteren terwijl u verdergaat.
Voorbereiden en wat u kunt verwachten
De casestudy Het Klembord-voorbeeld overzetten naar C++/WinRT van C# illustreert voorbeelden van de soorten beslissingen over softwareontwerp die u neemt tijdens het overzetten van een project naar C++/WinRT. Het is dus een goed idee om u voor te bereiden op porting door een goed inzicht te krijgen in de werking van de bestaande code. Op die manier krijgt u een goed overzicht van de functionaliteit van de app en de structuur van de code. De beslissingen die u neemt, zullen u altijd verder brengen in de juiste richting.
In termen van wat voor soort overdrachtswijzigingen u kunt verwachten, kunt u deze groeperen in vier categorieën.
-
De taalprojectieporteren. De Windows Runtime (WinRT) wordt geprojecteerd in verschillende programmeertalen. Elk van deze taalprojecties is ontworpen om idiomatisch te voelen voor de betreffende programmeertaal. Voor C# worden sommige Windows Runtime-typen geprojecteerd als .NET-typen. U vertaalt bijvoorbeeld System.Collections.Generic.IReadOnlyList<T> terug naar Windows.Foundation.Collections.IVectorView<T>. In C# worden sommige Windows Runtime-bewerkingen ook geprojecteerd als handige C#-taalfuncties. Een voorbeeld is dat u in C# de syntaxis van de operator
+=gebruikt om een gemachtigde voor gebeurtenisafhandeling te registreren. U vertaalt dus taalfuncties zoals die terug naar de fundamentele bewerking die wordt uitgevoerd (gebeurtenisregistratie in dit voorbeeld). -
syntaxis van de poorttaal. Veel van deze wijzigingen zijn eenvoudige mechanische transformaties, waarbij het ene symbool voor het andere wordt vervangen. Als u bijvoorbeeld een punt (
.) wijzigt in een dubbele punt (::). -
procedure voor poorttaal. Sommige van deze kunnen eenvoudige, terugkerende wijzigingen zijn (zoals
myObject.MyPropertyinmyObject.MyProperty()). Anderen hebben diepere wijzigingen nodig (bijvoorbeeld het overzetten van een procedure waarbij het gebruik van System.Text.StringBuilder is vereist voor een procedure waarbij gebruik wordt gemaakt van std::wostringstream). -
Portering-gerelateerde taken die specifiek zijn voor C++/WinRT. Bepaalde details van de Windows Runtime worden impliciet verzorgd door C#, achter de schermen. Deze details worden expliciet uitgevoerd in C++/WinRT. Een voorbeeld is dat u een
.idl-bestand gebruikt om uw runtimeklassen te definiëren.
Na de op taken gebaseerde index die volgt, zijn de rest van de secties in dit onderwerp gestructureerd volgens de bovenstaande taxonomie.
Inhoud zoeken op basis van de taak die u uitvoert
| Opdracht | Inhoud |
|---|---|
| Een Windows Runtime-onderdeel maken (WRC) | Bepaalde functionaliteit kan alleen worden bereikt (of bepaalde API's die worden aangeroepen) met C++. U kunt deze functionaliteit in een C++/WinRT WRC inschakelen en vervolgens de WRC gebruiken vanuit (bijvoorbeeld) een C#-app. Zie Windows Runtime-onderdelen met C++/WinRT- en Als u een runtimeklasse maakt in een Windows Runtime-onderdeel. |
| Een asynchrone methode overzetten | Het is een goed idee als de eerste regel van een asynchrone methode in een C++/WinRT-klasse voor runtime auto lifetime = get_strong(); te zijn (zie Veilig toegang krijgen tot de -aanwijzer in een coroutine van een klasse-lid).Overdracht van Task, zie Asynchrone actie.Porteren vanaf Task<T>, zie Asynchrone operatie.Overzetten van async void, zie Fire-and-forget-methode. |
| Een klasse overzetten | Bepaal eerst of de klasse een runtimeklasse moet zijn of dat deze een gewone klasse kan zijn. Zie het begin van Author API's met C++/WinRTom u te helpen dat te bepalen. Bekijk vervolgens de volgende drie rijen hieronder. |
| Een runtimeklasse overzetten | Een klasse die functionaliteit deelt buiten de C++-app of een klasse die wordt gebruikt in XAML-gegevensbinding. Zie Als u een runtimeklasse maakt in een Windows Runtime-onderdeelof Als u een runtimeklasse maakt waarnaar moet worden verwezen in de XAML-gebruikersinterface. Deze koppelingen beschrijven dit in meer detail, maar een runtimeklasse moet worden gedeclareerd in IDL. Als uw project al een IDL-bestand bevat (bijvoorbeeld Project.idl), wordt u aangeraden een nieuwe runtimeklasse in dat bestand te declareren. Declareer in IDL alle methoden en gegevensleden die buiten uw app worden gebruikt of die worden gebruikt in XAML. Nadat u het IDL-bestand hebt bijgewerkt, bouwt u het bestand opnieuw en bekijkt u de gegenereerde stub-bestanden (.h en .cpp) in de Generated Files map van uw project (in Solution Explorer, waarbij het projectknooppunt is geselecteerd, controleert u of Alle bestanden weergeven is ingeschakeld). Vergelijk de stub-bestanden met de bestanden die al in uw project aanwezig zijn, voeg zo nodig bestanden toe of voeg functiehandtekeningen toe of werk deze bij. Stub-bestandssyntaxis is altijd correct, dus we raden u aan deze te gebruiken om buildfouten te minimaliseren. Zodra de stubs in uw project overeenkomen met die in de stub-bestanden, kunt u deze implementeren door de C#-code over te zetten. |
| Een gewone klasse overzetten | Zie als u geen runtime-klasse ontwerpt. |
| Auteur IDL |
Inleiding tot Microsoft Interface Definition Language 3.0 Als u een runtimeklasse maakt waarnaar moet worden verwezen in de XAML-gebruikersinterface Objecten gebruiken uit XAML-markup Definieer uw runtime-klassen in IDL |
| Een verzameling overzetten |
Verzamelingen met C++/WinRT Een gegevensbron beschikbaar maken voor XAML-markeringen koppelende container vectorlidtoegang |
| Een gebeurtenis overzetten |
Gebeurtenishandler delegeren als klasselid Intrekken gebeurtenishandlergedelegeerde |
| Een methode overzetten | Vanuit C#: private async void SampleButton_Tapped(object sender, Windows.UI.Xaml.Input.TappedRoutedEventArgs e) { ... }Naar het bestand C++/WinRT .h: fire_and_forget SampleButton_Tapped(IInspectable const&, RoutedEventArgs const&);Naar het bestand C++/WinRT .cpp: fire_and_forget OcrFileImage::SampleButton_Tapped(IInspectable const&, RoutedEventArgs const&) {...} |
| Poorttekenreeksen |
Verwerking van tekenreeksen in C++/WinRT ToString tekenreeksopbouw Converteren en ontpakken van een tekenreeks |
| Typeconversie (typeomzetting) | C#: o.ToString()C++/WinRT: to_hstring(static_cast<int>(o))Zie ook ToString. C#: (Value)oC++/WinRT: unbox_value<Value>(o)Werpt als het uitpakken mislukt. Zie ook Boxing en Unboxing. C#: o as Value? ?? fallbackC++/WinRT: unbox_value_or<Value>(o, fallback)Geeft de standaardwaarde terug als het uitpakken mislukt. Zie ook Boxing en Unboxing. C#: (Class)oC++/WinRT: o.as<Class>()Werpt als de conversie mislukt. C#: o as ClassC++/WinRT: o.try_as<Class>()Retourneert null als de conversie mislukt. |
Wijzigingen die betrekking hebben op de taalprojectie
| Categorie | C# | C++/WinRT | Zie ook |
|---|---|---|---|
| Ongedefinieerd object |
objectof System.Object |
Windows::Foundation::IInspectable | Overzetten van de EnableClipboardContentChangedNotifications methode |
| Projectienaamruimten | using System; |
using namespace Windows::Foundation; |
|
using System.Collections.Generic; |
using namespace Windows::Foundation::Collections; |
||
| Grootte van een verzameling | collection.Count |
collection.Size() |
Het overzetten van de methode BuildClipboardFormatsOutputString |
| Typisch verzamelingstype | IList<T->en Voeg toe om een element toe te voegen. | IVector<T->en toevoegen om een element toe te voegen. Als u ergens een std::vector gebruikt, kunt u met push_back een element toevoegen. | |
| Alleen-lezen-verzamelingstype | IReadOnlyList<T> | IVectorView<T> | Het overzetten van de methode BuildClipboardFormatsOutputString |
| Gebeurtenishandler delegeren als klasselid | myObject.EventName += Handler; |
token = myObject.EventName({ get_weak(), &Class::Handler }); |
Overzetten van de EnableClipboardContentChangedNotifications methode |
| Gedelegeerde gebeurtenisafhandelaar opheffen | myObject.EventName -= Handler; |
myObject.EventName(token); |
Overzetten van de EnableClipboardContentChangedNotifications methode |
| Associatieve container | IDictionary<K, V> | IMap<K, V> | |
| Vectorleden-toegang | x = v[i];v[i] = x; |
x = v.GetAt(i);v.SetAt(i, x); |
Een gebeurtenis-handler registreren/intrekken
In C++/WinRT hebt u verschillende syntactische opties voor het registreren/intrekken van een gemachtigde voor een gebeurtenis-handler, zoals beschreven in Gebeurtenissen verwerken met behulp van gemachtigden in C++/WinRT-. Zie ook Het porteren van de EnableClipboardContentChangedNotifications methode.
Soms, bijvoorbeeld wanneer een gebeurtenisontvanger (een object dat een gebeurtenis behandelt) op het punt staat vernietigd te worden, wilt u misschien een gebeurtenis-handler intrekken zodat de gebeurtenisbron (het object dat de gebeurtenis aanroept) niet in een vernietigd object aanroept. Zie Het intrekken van een geregistreerde gemachtigde. In dergelijke gevallen maakt u een event_token lidvariabele voor uw eventhandlers. Zie bijvoorbeeld Porting the EnableClipboardContentChangedNotifications methode.
U kunt ook een gebeurtenis-handler registreren in XAML-markeringen.
<Button x:Name="OpenButton" Click="OpenButton_Click" />
In C# kan uw OpenButton_Click methode privé zijn en kan XAML deze nog steeds verbinden met de ButtonBase.Click gebeurtenis die wordt opgeroepen door OpenButton.
In C++/WinRT moet uw OpenButton_Click methode openbaar zijn in uw implementatietypeals u deze wilt registreren in XAML-markeringen. Als u een gebeurtenis-handler alleen registreert in imperatieve code, hoeft de gebeurtenis-handler niet openbaar te zijn.
namespace winrt::MyProject::implementation
{
struct MyPage : MyPageT<MyPage>
{
void OpenButton_Click(
winrt::Windows:Foundation::IInspectable const& sender,
winrt::Windows::UI::Xaml::RoutedEventArgs const& args);
}
};
U kunt ook de registrerende XAML-pagina een vriend van uw implementatietype maken en OpenButton_Click privé.
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);
}
};
Een laatste scenario is waar het C#-project dat u overzet, verbindt met de event handler vanuit markup (zie Functions in x:Bind) voor meer achtergrondinformatie over dat scenario.
<Button x:Name="OpenButton" Click="{x:Bind OpenButton_Click}" />
U kunt die markering gewoon wijzigen in de eenvoudigere Click="OpenButton_Click". Je kunt ook, als je wilt, die markeringen behouden zoals ze zijn. Het enige dat u hoeft te doen om het te ondersteunen, is de event handler in IDL te declareren.
void OpenButton_Click(Object sender, Windows.UI.Xaml.RoutedEventArgs e);
Opmerking
Declareer de functie als void, zelfs als u implementeren als Fire en vergeet.
Wijzigingen die betrekking hebben op de taalsyntaxis
| Categorie | C# | C++/WinRT | Zie ook |
|---|---|---|---|
| Toegangsaanpassingen | public \<member\> |
public:\<member\> |
de methode Button_Click overzetten |
| Toegang tot een gegevenslid | this.variable |
this->variable |
|
| Asynchrone actie | async Task ... |
IAsyncAction ... |
IAsyncAction interface, gelijktijdige en asynchrone operaties met C++/WinRT |
| Asynchrone bewerking | async Task<T> ... |
IAsyncOperation<T> ... |
IAsyncOperation interface, concurrentie en asynchrone bewerkingen met C++/WinRT |
| methode Fire-and-forget (impliceert asynchroon) | async void ... |
winrt::fire_and_forget ... |
de methode CopyButton_Click overzetten, Fire en vergeet |
| Toegang krijgen tot een geïnventariseerd constante | E.Value |
E::Value |
Overzetten van de DisplayChangedFormats-methode |
| Coöperatief wachten | await ... |
co_await ... |
De CopyButton_Click methode overzetten |
| Verzameling van geprojecteerde typen als een privéveld | private List<MyRuntimeClass> myRuntimeClasses = new List<MyRuntimeClass>(); |
std::vector<MyNamespace::MyRuntimeClass>m_myRuntimeClasses; |
|
| GUID-constructie | 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} }; |
|
| Scheidingsteken voor namespace | A.B.T |
A::B::T |
|
| Nul | null |
nullptr |
Het overzetten van de UpdateStatus methode |
| Een typeobject verkrijgen | typeof(MyType) |
winrt::xaml_typename<MyType>() |
de eigenschap Scenarios overzetten |
| Parameterdeclaratie voor een methode | MyType |
MyType const& |
parameter doorgeven |
| Parameterdeclaratie voor een asynchrone methode | MyType |
MyType |
parameter doorgeven |
| Een statische methode aanroepen | T.Method() |
T::Method() |
|
| Tekenreeksen |
stringof System.String |
winrt::hstring | Verwerking van tekenreeksen in C++/WinRT |
| Letterlijke tekenreeks | "a string literal" |
L"a string literal" |
de constructor overzetten, Huidigeen FEATURE_NAME |
| Afgeleid (of afgeleid) type | var |
auto |
Het overzetten van de methode BuildClipboardFormatsOutputString |
| Using-richtlijn | using A.B.C; |
using namespace A::B::C; |
de constructor overzetten, Huidigeen FEATURE_NAME |
| Letterlijk/ruwe tekenreeks-letteraliteit | @"verbatim string literal" |
LR"(raw string literal)" |
Het overzetten van de methode DisplayToast |
Opmerking
Als een headerbestand geen using namespace instructie voor een bepaalde naamruimte bevat, moet u alle typenamen voor die naamruimte volledig kwalificeren; of ze ten minste voldoende kwalificeren voor de compiler om ze te vinden. Zie voor een voorbeeld de methodeDisplayToast porting.
Overzetten van klassen en leden
U moet voor elk C#-type bepalen of u deze wilt overzetten naar een Windows Runtime-type of naar een reguliere C++-klasse/-struct/opsomming. Zie Het Klembord-voorbeeld overzetten naar C++/WinRT van C#voor meer informatie en gedetailleerde voorbeelden die illustreren hoe u deze beslissingen kunt nemen.
Een C#-eigenschap wordt doorgaans een accessorfunctie, een mutatorfunctie en een ondersteunend gegevenslid. Zie De eigenschap IsClipboardContentChangedEnabled portingvoor meer informatie en een voorbeeld.
Maak voor niet-statische velden gegevensleden van uw implementatietype .
Een statisch C#-veld wordt een statische C++/WinRT-toegangsfunctie en/of mutatorfunctie. Voor meer informatie en een voorbeeld, zie De constructor overzetten, Huidigeen FEATURE_NAME.
Voor lidfuncties moet u voor elke functie beslissen of deze deel uitmaakt van de IDL, of het een openbare of persoonlijke lidfunctie van uw implementatietype is. Zie IDL voor de MainPage typevoor meer informatie en voorbeelden van hoe u kunt beslissen.
XAML-markeringen en assetbestanden overzetten
In het geval van het Klembord-voorbeeld overzetten naar C++/WinRT van C#, konden we dezelfde XAML-markup (inclusief resources) en hulpmiddelenbestanden in het C#-project en het C++/WinRT-project gebruiken. In sommige gevallen zijn bewerkingen voor markeringen nodig om dat te bereiken. Zie De XAML en stijlen kopiëren die nodig zijn om het overzetten van MainPage-te voltooien.
Wijzigingen die betrekking hebben op procedures in de taal
| Categorie | C# | C++/WinRT | Zie ook |
|---|---|---|---|
| Levensduurbeheer in een asynchrone methode | Niet van toepassing. |
auto lifetime{ get_strong() }; ofauto lifetime = get_strong(); |
De CopyButton_Click methode overzetten |
| Verwijdering | using (var t = v) |
auto t{ v };t.Close(); // or let wrapper destructor do the work |
Het porteren van de CopyImage methode |
| Object samenstellen | new MyType(args) |
MyType{ args } ofMyType(args) |
de eigenschap Scenarios overzetten |
| Niet-geïnitialiseerde verwijzing maken | MyType myObject; |
MyType myObject{ nullptr }; ofMyType myObject = nullptr; |
de constructor overzetten, Huidigeen FEATURE_NAME |
| Object samenstellen in een variabele met args | var myObject = new MyType(args); |
auto myObject{ MyType{ args } }; of auto myObject{ MyType(args) }; of auto myObject = MyType{ args }; of auto myObject = MyType(args); of MyType myObject{ args }; of MyType myObject(args); |
De methode Footer_Click porten |
| Object maken in variabele zonder argumenten | var myObject = new T(); |
MyType myObject; |
Het overzetten van de methode BuildClipboardFormatsOutputString |
| Verkorte initialisatie van objecten | var p = new FileOpenPicker{ViewMode = PickerViewMode.List}; |
FileOpenPicker p;p.ViewMode(PickerViewMode::List); |
|
| Bulkvectorbewerking | var p = new FileOpenPicker{FileTypeFilter = { ".png", ".jpg", ".gif" }}; |
FileOpenPicker p;p.FileTypeFilter().ReplaceAll({ L".png", L".jpg", L".gif" }); |
De CopyButton_Click methode overzetten |
| Itereren over verzameling | foreach (var v in c) |
for (auto&& v : c) |
Het overzetten van de methode BuildClipboardFormatsOutputString |
| Een uitzondering vangen | catch (Exception ex) |
catch (winrt::hresult_error const& ex) |
De methode PasteButton_Click overzetten |
| Details van uitzondering | ex.Message |
ex.message() |
De methode PasteButton_Click overzetten |
| Een eigenschapswaarde ophalen | myObject.MyProperty |
myObject.MyProperty() |
de methode NotifyUser porting |
| Een eigenschapswaarde instellen | myObject.MyProperty = value; |
myObject.MyProperty(value); |
|
| Een eigenschapswaarde verhogen | myObject.MyProperty += v; |
myObject.MyProperty(thing.Property() + v);Voor tekenreeksen schakelt u over naar een opbouwfunctie |
|
| ToString() | myObject.ToString() |
winrt::to_hstring(myObject) |
ToString() |
| Taaltekenreeks naar Windows Runtime-tekenreeks | Niet van toepassing. | winrt::hstring{ s } |
|
| Stringopbouw | StringBuilder builder;builder.Append(...); |
std::wostringstream builder;builder << ...; |
tekenreeksopbouw |
| Tekenreeksinterpolatie | $"{i++}) {s.Title}" |
winrt::to_hstringen/of winrt::hstring::operator+ | Porting van de OnNavigatedTo methode |
| Lege tekenreeks voor vergelijking | System.String.Empty | winrt::hstring::empty | Het overzetten van de UpdateStatus methode |
| Lege tekenreeks maken | var myEmptyString = String.Empty; |
winrt::hstring myEmptyString{ L"" }; |
|
| Woordenlijstbewerkingen | 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) |
|
| Typeconversie (bij foutmelding) | (MyType)v |
v.as<MyType>() |
De methode Footer_Click porten |
| Typeconversie (null bij fout) | v as MyType |
v.try_as<MyType>() |
De methode PasteButton_Click overzetten |
| XAML-elementen met x:Name zijn eigenschappen | MyNamedElement |
MyNamedElement() |
de constructor overzetten, Huidigeen FEATURE_NAME |
| Overschakelen naar de ui-thread | CoreDispatcher.RunAsync | CoreDispatcher.RunAsyncof winrt::resume_foreground | de methodeNotifyUser porting and Porting the HistoryAndRoaming method |
| Ui-elementconstructie in imperatieve code op een XAML-pagina | Zie UI-elementconstructie | Zie UI-elementconstructie |
In de volgende secties wordt dieper ingegaan op een aantal items in de tabel.
UI-elementconstructie
Deze codevoorbeelden tonen de constructie van een UI-element in de imperatieve code van een XAML-pagina.
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()
C#-typen bieden de methode Object.ToString.
int i = 2;
var s = i.ToString(); // s is a System.String with value "2".
C++/WinRT biedt deze faciliteit niet rechtstreeks, maar u kunt ook alternatieven gebruiken.
int i{ 2 };
auto s{ std::to_wstring(i) }; // s is a std::wstring with value L"2".
C++/WinRT ondersteunt ook winrt::to_hstring voor een beperkt aantal typen. Je moet extra overbelastingen toevoegen voor elk extra type dat je naar een string wilt omzetten.
| Taal | Omzetten naar string | Enum naar string converteren |
|---|---|---|
| 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); |
In het geval van het omzetten van een enum naar een string, moet u de implementatie van winrt::to_hstringopgeven.
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));
}
}
}
Deze stringificaties worden vaak impliciet verwerkt door middel van gegevensbinding.
<TextBlock>
You have <Run Text="{Binding FlowerCount}"/> flowers.
</TextBlock>
<TextBlock>
Most recent status is <Run Text="{x:Bind LatestOperation.Status}"/>.
</TextBlock>
Deze bindingen voeren winrt::to_hstring van de gebonden eigenschap uit. In het geval van het tweede voorbeeld (de StatusEnum), moet u uw eigen overload van winrt::to_hstringdefiniëren, anders krijgt u een compilerfout.
Zie ook De Footer_Click methode overzetten.
Stringopbouw
Voor het bouwen van tekenreeksen heeft C# een ingebouwd tekenreeksbouwer-type.
| Categorie | C# | C++/WinRT |
|---|---|---|
| Stringopbouw | StringBuilder builder;builder.Append(...); |
std::wostringstream builder;builder << ...; |
| Een Windows Runtime-tekenreeks toevoegen, met behoud van null-waarden | builder.Append(s); |
builder << std::wstring_view{ s }; |
| Een nieuwe regel toevoegen | builder.Append(Environment.NewLine); |
builder << std::endl; |
| Het resultaat openen | s = builder.ToString(); |
ws = builder.str(); |
Zie ook het aanpassen van de BuildClipboardFormatsOutputString methodeen het aanpassen van de DisplayChangedFormats methode.
Code uitvoeren op de hoofd-UI-thread
Dit voorbeeld is afkomstig uit het voorbeeld van de streepjescodescanner.
Als u wilt werken aan de hoofd-UI-thread in een C#-project, gebruikt u doorgaans de methode CoreDispatcher.RunAsync, zoals deze.
private async void Watcher_Added(DeviceWatcher sender, DeviceInformation args)
{
await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
// Do work on the main UI thread here.
});
}
Het is veel eenvoudiger om dat in C++/WinRT uit te drukken. U ziet dat we parameters accepteren per waarde, uitgaande van de veronderstelling dat we ze na het eerste ophangpunt willen aanspreken (de co_awaitin dit geval). Voor meer informatie, zie Parameter-passing.
winrt::fire_and_forget Watcher_Added(DeviceWatcher sender, winrt::DeviceInformation args)
{
co_await Dispatcher();
// Do work on the main UI thread here.
}
Als u het werk met een andere prioriteit dan de standaardwaarde wilt uitvoeren, raadpleegt u de winrt::resume_foreground functie, die een overload-variant heeft waarmee u een prioriteit kunt opgeven. Zie voor codevoorbeelden die laten zien hoe u een oproep naar winrt::resume_foregroundkunt afwachten, Programmeren met threadaffiniteit in gedachten.
Taken voor portering die specifiek zijn voor C++/WinRT
Definieer uw runtime-klassen in IDL
Zie IDL voor de MainPage type, en consolideer uw .idl-bestanden.
Neem de C++/WinRT Windows-naamruimteheaderbestanden op die u nodig hebt
Wanneer u in C++/WinRT een type uit een Windows-naamruimte wilt gebruiken, moet u het bijbehorende C++/WinRT Windows-naamruimteheaderbestand opnemen. Zie bijvoorbeeld Porting the NotifyUser method.
Verpakken en uitpakken
C# zet scalairs automatisch om in objecten. C++/WinRT vereist dat u de functie winrt::box_value expliciet aanroept. In beide talen moet u expliciet uitpakken. Zie Verpakken en uitpakken met C++/WinRT.
In de volgende tabellen gebruiken we deze definities.
| C# | C++/WinRT |
|---|---|
int i; |
int i; |
string s; |
winrt::hstring s; |
object o; |
IInspectable o; |
| Operatie | C# | C++/WinRT |
|---|---|---|
| Boksen | o = 1;o = "string"; |
o = box_value(1);o = box_value(L"string"); |
| Uitpakken | i = (int)o;s = (string)o; |
i = unbox_value<int>(o);s = unbox_value<winrt::hstring>(o); |
C++/CX en C# veroorzaken uitzonderingen als u probeert een null-aanwijzer naar een waardetype te unboxen. C++/WinRT beschouwt deze als een programmeerfout en loopt vast. Gebruik in C++/WinRT de functie winrt::unbox_value_or als u de case wilt afhandelen waarin het object niet van het type is dat u dacht dat het was.
| Scenariobeschrijving | C# | C++/WinRT |
|---|---|---|
| Haal een bekend geheel getal uit de verpakking | i = (int)o; |
i = unbox_value<int>(o); |
| Als o null is | System.NullReferenceException |
Ongeluk |
| Indien o geen 'boxed int' is | System.InvalidCastException |
Ongeluk |
| Haal int uit de verpakking, gebruik een backup als het null is; crasht bij andere waarden. | i = o != null ? (int)o : fallback; |
i = o ? unbox_value<int>(o) : fallback; |
| Doos integer uitpakken indien mogelijk; alternatieve methode gebruiken voor iets anders | i = as int? ?? fallback; |
i = unbox_value_or<int>(o, fallback); |
Zie bijvoorbeeld De methode OnNavigatedToporting and Porting the Footer_Click method.
Het boxen en unboxen van een tekenreeks
Een tekenreeks is in bepaalde opzichten een waardetype en in andere opzichten een verwijzingstype. C# en C++/WinRT behandelen tekenreeksen anders.
Het ABI-type HSTRING is een pointer naar een referentiegetelde tekenreeks. Maar het is niet afgeleid van IInspectable, dus het is technisch geen object. Bovendien vertegenwoordigt een null-HSTRING- de lege tekenreeks. Het verpakken van objecten die niet zijn afgeleid van IInspectable wordt uitgevoerd door ze te verpakken in een IReference<T>, en de Windows Runtime biedt een standaardimplementatie in de vorm van het PropertyValue-object (aangepaste typen worden gerapporteerd als PropertyType::OtherType).
C# vertegenwoordigt een Windows Runtime-tekenreeks als referentietype; terwijl C++/WinRT een tekenreeks projecteert als een waardetype. Dit betekent dat een in een vak geplaatste null-tekenreeks verschillende weergaven kan hebben, afhankelijk van hoe u daar bent gekomen.
| Gedrag | C# | C++/WinRT |
|---|---|---|
| Verklaringen | object o;string s; |
IInspectable o;hstring s; |
| Categorie tekenreekstype | Verwijzingstype | Waardetype |
| HSTRING projecten als null | "" |
hstring{} |
Zijn null en "" identiek? |
Nee. | Ja |
| Geldigheid van null | s = null;s.Length genereert NullReferenceException |
s = hstring{};s.size() == 0 (geldig) |
| Als u null-tekenreeks toewijst aan object | o = (string)null;o == null |
o = box_value(hstring{});o != nullptr |
Als u "" aan object toewijst |
o = "";o != null |
o = box_value(hstring{L""});o != nullptr |
Eenvoudige boxing en unboxing.
| Operatie | C# | C++/WinRT |
|---|---|---|
| Een tekenreeks in een doos plaatsen | o = s;Een lege tekenreeks wordt een niet-nul-object. |
o = box_value(s);Een lege tekenreeks wordt een niet-nul-object. |
| Een bekende reeks uitpakken | s = (string)o;Null-object wordt null-tekenreeks. InvalidCastException als het geen tekenreeks is. |
s = unbox_value<hstring>(o);Null-object loopt vast. Crash als het geen tekenreeks is. |
| Een mogelijke tekenreeks uitpakken | s = o as string;Een null-object of geen tekenreeks wordt een null-tekenreeks. OF s = o as string ?? fallback;Nul of niet-tekstrijk wordt omgezet naar de terugvaloptie. Lege string gehandhaafd. |
s = unbox_value_or<hstring>(o, fallback);Nul of niet-tekstrijk wordt omgezet naar de terugvaloptie. Lege string gehandhaafd. |
Een klasse beschikbaar maken voor de markeringsextensie {Binding}
Als u de markeringsextensie {Binding} wilt gebruiken om gegevens te binden aan uw gegevenstype, raadpleegt u Bindingsobject dat is gedeclareerd met {Binding}.
Objecten uit XAML-markeringen consumeren
In een C#-project kunt u privéleden en benoemde elementen uit XAML-markeringen gebruiken. Maar in C++/WinRT moeten alle entiteiten die worden gebruikt met behulp van de XAML-{x:Bind}-markeringsextensie openbaar worden weergegeven in IDL.
Als u een Booleaanse waarde bindt, wordt true of false in C# weergegeven, maar wordt Windows.Foundation.IReference\`1<Booleaanse> in C++/WinRT weergegeven.
Zie Objecten gebruiken uit markupvoor codevoorbeelden en meer informatie.
Een gegevensbron beschikbaar maken voor XAML-markeringen
In C++/WinRT versie 2.0.190530.8 of hoger maakt winrt::single_threaded_observable_vector een waarneembare vector die ondersteuning biedt voor zowel IObservableVector<T> als IObservableVector<IInspectable>. Zie voor een voorbeeld de scenario-eigenschapoverzetten.
U kunt uw Midl-bestand (.idl) als volgt schrijven (zie ook Factoring runtime classes in Midl-bestanden (.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; };
}
}
En implementeer zo.
// 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;
};
...
Zie voor meer informatie over besturingselementen van XAML-items, het binden aan een C++/WinRT-verzamelingen de Verzamelingen met C++/WinRT.
Een gegevensbron beschikbaar maken voor XAML-opmaak (vóór C++/WinRT 2.0.190530.8)
XAML-gegevensbinding vereist dat een itemsbron IIterable<IInspectable>implementeert, evenals een van de volgende combinaties van interfaces.
- IObservableVector<IInspectable>
- IBindableVector en INotifyCollectionChanged
- IBindableVector en IBindableObservableVector
- IBindableVector zelf (reageert niet op wijzigingen)
- IVector<IInspectable>
- IBindableIterable (worden elementen herhaald en opgeslagen in een persoonlijke verzameling)
Een algemene interface, zoals IVector<T->, kan tijdens runtime niet worden gedetecteerd. Elke IVector<T-> heeft een andere interface-id (IID), een functie van T-. Elke ontwikkelaar kan de set van T willekeurig uitbreiden, zodat de XAML-bindingscode nooit de volledige set kan kennen waarvoor een query moet worden uitgevoerd. Deze beperking is geen probleem voor C# omdat elk CLR-object dat IEnumerable implementeert<T-> automatisch IEnumerableimplementeert. Op ABI-niveau betekent dit dat elk object dat IObservableVector implementeert<T> automatisch IObservableVector<IInspectable>implementeert.
C++/WinRT biedt geen garantie. Als een C++/WinRT-runtimeklasse IObservableVector<T->implementeert, kunnen we er niet van uitgaan dat een implementatie van IObservableVector<IInspectable> ook wordt geboden.
Daarom moet het vorige voorbeeld er als volgt uitzien.
...
runtimeclass BookstoreViewModel
{
// This is really an observable vector of BookSku.
Windows.Foundation.Collections.IObservableVector<Object> BookSkus{ get; };
}
En de uitvoering.
// 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;
};
...
Als u toegang wilt krijgen tot objecten in m_bookSkus, moet u ze weer terugzetten naar boekwinkel::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;
}
Afgeleide klassen
Als u wilt afleiden van een runtimeklasse, moet de basisklasse composablezijn. C# vereist niet dat u speciale stappen uitvoert om uw klassen composable te maken, maar C++/WinRT wel. U gebruikt de niet-verzegelde trefwoorden om aan te geven dat uw klasse bruikbaar moet zijn als basisklasse.
unsealed runtimeclass BasePage : Windows.UI.Xaml.Controls.Page
{
...
}
runtimeclass DerivedPage : BasePage
{
...
}
In het headerbestand voor het implementatietypemoet u het headerbestand van de basisklasse opnemen voordat u de automatisch gegenereerde header voor de afgeleide klasse opneemt. Anders krijgt u fouten zoals 'Ongeldig gebruik van dit type als een expressie'.
// 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>
{
...
}
}