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.
Hint
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 in dit onderwerp.
Dit onderwerp biedt een uitgebreid overzicht van de technische details die komen kijken bij het overzetten van de broncode van een C#-project naar de equivalente code in C++/WinRT.
Voor een casestudy van het overzetten van een van de Universal Windows Platform (UWP) app-voorbeelden raadpleegt u het bijbehorende onderwerp Het Klembord-voorbeeld overzetten naar C++/WinRT van C#. U kunt oefenen met het overzetten en ervaring opdoen door die stapsgewijze handleiding te volgen en onderweg zelf het voorbeeld over te zetten.
Voorbereiden en wat u kunt verwachten
De casestudy Het Clipboard-voorbeeld overzetten van C# naar C++/WinRT illustreert welke ontwerpkeuzes voor software u moet maken bij 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, en zorgen de beslissingen die u vervolgens neemt er altijd voor dat u vooruitgaat en de juiste richting op gaat.
In termen van wat voor soort overdrachtswijzigingen u kunt verwachten, kunt u deze groeperen in vier categorieën.
-
De taalprojectie overzetten. De Windows Runtime (WinRT) wordt in verschillende programmeertalen geprojecteerd. 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>. Ook in C# worden sommige Windows Runtime bewerkingen 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 poorttaal. Veel van deze wijzigingen zijn eenvoudige mechanische transformaties, waarbij het ene symbool voor het andere wordt vervangen. Bijvoorbeeld: een punt (
.) veranderen in een dubbele punt (::). -
Taalprocedure voor de poort. Sommige hiervan kunnen eenvoudige, herhaalde wijzigingen zijn (zoals
myObject.MyPropertynaarmyObject.MyProperty()). Anderen hebben diepere wijzigingen nodig (bijvoorbeeld het overzetten van een procedure waarbij System.Text.StringBuilder wordt gebruikt voor een procedure waarbij std::wostringstream wordt gebruikt). -
Overdrachtsgerelateerde 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
.idlbestand 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
| Task | Content |
|---|---|
| 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 in een Windows Runtime-onderdeel maakt. |
| Een asynchrone methode overzetten | Het is een goed idee dat de eerste regel van een asynchrone methode in een C++/WinRT-runtimeklasse auto lifetime = get_strong(); is (zie Veilig toegang krijgen tot de this-pointer in een coroutine van een klassenlid).Porteren vanuit Task, zie Asynchrone actie.Porteren vanuit Task<T>, zie asynchrone bewerking.Migreren vanuit 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++/WinRT om 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. Kijk of u een runtimeklasse in een Windows Runtime-onderdeel maakt of als u een runtimeklasse ontwerpt waarnaar moet worden verwezen in uw 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), raden we u aan 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 opnieuw en bekijkt u de gegenereerde stub-bestanden (.hen .cpp) in de map van Generated Files 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 schrijft. |
| Auteur IDL |
Inleiding tot Microsoft Interface Definition Language 3.0 Als u een runtime-klasse maakt waarnaar wordt verwezen in uw XAML-gebruikersinterface Objecten uit XAML-opmaak gebruiken Uw runtimeklassen definiëren in IDL |
| Een verzameling overzetten |
Verzamelingen met C++/WinRT Een gegevensbron beschikbaar maken voor XAML-markeringen Associatieve container Vectorlidtoegang |
| Een gebeurtenis overzetten |
Eventhandler-delegate als lid van een klasse Event-handlerdelegate intrekken |
| Een methode overzetten | Vanuit C#: private async void SampleButton_Tapped(object sender, Microsoft.UI.Xaml.Input.TappedRoutedEventArgs e) { ... }Naar het C++/WinRT-bestand .h : fire_and_forget SampleButton_Tapped(IInspectable const&, RoutedEventArgs const&);Naar het C++/WinRT-bestand .cpp : fire_and_forget OcrFileImage::SampleButton_Tapped(IInspectable const&, RoutedEventArgs const&) {...} |
| Poorttekenreeksen |
Verwerking van tekenreeksen in C++/WinRT ToString Strings samenstellen Boksen en het uitpakken van een tekenreeks opheffen |
| Typeconversie (type casting) | 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 Boksen en uitpakken. C#: o as Value? ?? fallbackC++/WinRT: unbox_value_or<Value>(o, fallback)Geeft de fallbackwaarde terug als het unboxen mislukt. Zie ook Inpakken en uitpakken. 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
| Category | C# | C++/WinRT | Zie ook |
|---|---|---|---|
| Object zonder type |
objectof System.Object |
Windows::Foundation::IInspectable | De methode EnableClipboardContentChangedNotifications overzetten |
| Projectienaamruimten | using System; |
using namespace Windows::Foundation; |
|
using System.Collections.Generic; |
using namespace Windows::Foundation::Collections; |
||
| Grootte van een verzameling | collection.Count |
collection.Size() |
De methode BuildClipboardFormatsOutputString overzetten |
| Typisch verzamelingstype | IList<T> en Toevoegen om een element toe te voegen. | IVector<T> en Toevoegen om een element toe te voegen. Als u ergens een std::vector gebruikt, push_back om een element toe te voegen. | |
| Verzamelingstype alleen-lezen | IReadOnlyList<T> | IVectorView<T> | De methode BuildClipboardFormatsOutputString overzetten |
| Eventhandler-delegate als lid van een klasse | myObject.EventName += Handler; |
token = myObject.EventName({ get_weak(), &Class::Handler }); |
De methode EnableClipboardContentChangedNotifications overzetten |
| Eventhandler-delegate intrekken | myObject.EventName -= Handler; |
myObject.EventName(token); |
De methode EnableClipboardContentChangedNotifications overzetten |
| Associatieve verzameling | IDictionary<K, V> | IMap<K, V> | |
| Vectorlidtoegang | 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 Handle events by using delegates in C++/WinRT. Zie ook de methode EnableClipboardContentChangedNotifications overzetten.
Soms wilt u bijvoorbeeld, wanneer een gebeurtenisontvanger (een object dat een gebeurtenis afhandelt) op het punt staat te worden vernietigd, een gebeurtenisafhandelaar verwijderen zodat de gebeurtenisbron (het object dat de gebeurtenis activeert) geen vernietigd object meer aanroept. Zie Een geregistreerde gemachtigde intrekken. In dergelijke gevallen maakt u voor uw gebeurtenisverwerkers een lidvariabele event_token aan. Zie voor een voorbeeld De methode EnableClipboardContentChangedNotifications overzetten.
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 door OpenButton wordt gegenereerd.
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::Microsoft::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::Microsoft::UI::Xaml::RoutedEventArgs const& args);
}
};
Een laatste scenario is dat het C#-project dat u overzet bindt aan de eventhandler in de markup (meer achtergrond over dat scenario vindt u in Functions in x:Bind).
<Button x:Name="OpenButton" Click="{x:Bind OpenButton_Click}" />
U kunt die markering gewoon wijzigen in de eenvoudigere Click="OpenButton_Click". Of, als u wilt, kunt u die markeringen behouden zoals het is. Het enige wat u hoeft te doen om dit te ondersteunen, is de gebeurtenisafhandelaar in IDL declareren.
void OpenButton_Click(Object sender, Microsoft.UI.Xaml.RoutedEventArgs e);
Note
Declareer de functie als void zelfs als je die implementeert als Fire and forget.
Wijzigingen die betrekking hebben op de taalsyntaxis
| Category | C# | C++/WinRT | Zie ook |
|---|---|---|---|
| Toegangsaanpassingen | public \<member\> |
public:\<member\> |
De Button_Click-methode overzetten |
| Toegang tot een gegevenslid | this.variable |
this->variable |
|
| Asynchrone actie | async Task ... |
IAsyncAction ... |
IAsyncAction-interface, gelijktijdigheid en asynchrone bewerkingen met C++/WinRT |
| Asynchrone bewerking | async Task<T> ... |
IAsyncOperation<T> ... |
IAsyncOperation-interface, gelijktijdigheid en asynchrone bewerkingen met C++/WinRT |
| Fire-and-forget-methode (impliceert asynchrone uitvoering) | async void ... |
winrt::fire_and_forget ... |
De CopyButton_Click methode overzetten, Fire en vergeet |
| Toegang krijgen tot een geïnventariseerd constante | E.Value |
E::Value |
De methode DisplayChangedFormats overzetten |
| Coöperatief wachten | await ... |
co_await ... |
De CopyButton_Click-methode overzetten |
| Verzameling van projectietypen 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 van naamruimte | A.B.T |
A::B::T |
|
| Null | null |
nullptr |
De methode UpdateStatus overzetten |
| Een typeobject verkrijgen | typeof(MyType) |
winrt::xaml_typename<MyType>() |
De eigenschap Scenario's overzetten |
| Parameterdeclaratie voor een methode | MyType |
MyType const& |
Parameteroverdracht |
| Parameterdeclaratie voor een asynchrone methode | MyType |
MyType |
Parameteroverdracht |
| 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" |
Het overzetten van de constructor, Current en FEATURE_NAME |
| Afgeleid (of gededuceerd) type | var |
auto |
De methode BuildClipboardFormatsOutputString overzetten |
| Using-directive | using A.B.C; |
using namespace A::B::C; |
De constructor, huidige en FEATURE_NAME overzetten |
| letterlijke/onbewerkte stringliteral | @"verbatim string literal" |
LR"(raw string literal)" |
De DisplayToast-methode overzetten |
Note
Als een headerbestand geen instructie voor een bepaalde naamruimte bevat using namespace , moet u alle typenamen voor die naamruimte volledig in aanmerking nemen of ten minste voldoende kwalificeren voor de compiler om ze te vinden. Zie voor een voorbeeld de methode DisplayToast overzetten.
Klassen en leden overzetten
U moet voor elk C#-type bepalen of u het 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 omgezet in een accessorfunctie, een mutatorfunctie en een onderliggend gegevenslid. Zie De eigenschap IsClipboardContentChangedEnabled overzetten voor meer informatie en een voorbeeld.
Voor niet-statische velden moet u gegevensleden van uw implementatietype maken.
Een statisch C#-veld wordt een statische C++/WinRT-toegangsfunctie en/of mutatorfunctie. Zie De constructor, Current en FEATURE_NAME overzetten voor meer informatie, en een voorbeeld.
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 het type MainPage voor meer informatie en voorbeelden van hoe u kunt beslissen.
Het overzetten van XAML-opmaak en assetbestanden
In het geval van het overzetten van het Klembord-voorbeeld naar C++/WinRT vanuit C#, konden we dezelfde XAML-markeringen (inclusief resources) en assetbestanden in de C# en het C++/WinRT-project gebruiken. In sommige gevallen zijn bewerkingen voor markeringen nodig om dat te bereiken. Zie Kopiëren van de XAML en stijlen die nodig zijn om de overdracht van MainPage te voltooien.
Wijzigingen die betrekking hebben op procedures in de taal
| Category | C# | C++/WinRT | Zie ook |
|---|---|---|---|
| Levensduurbeheer in een asynchrone methode | N/A |
auto lifetime{ get_strong() }; ofauto lifetime = get_strong(); |
De CopyButton_Click-methode overzetten |
| Afstoting | using (var t = v) |
auto t{ v };t.Close(); // or let wrapper destructor do the work |
De methode CopyImage overzetten |
| Object maken | new MyType(args) |
MyType{ args } ofMyType(args) |
De eigenschap Scenario's overzetten |
| Niet-geïnitialiseerde verwijzing maken | MyType myObject; |
MyType myObject{ nullptr }; ofMyType myObject = nullptr; |
Overzetten van de constructor, Current en 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 Footer_Click-methode overzetten |
| Object maken in variabele zonder argumenten | var myObject = new T(); |
MyType myObject; |
De methode BuildClipboardFormatsOutputString overzetten |
| 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 een verzameling | foreach (var v in c) |
for (auto&& v : c) |
De methode BuildClipboardFormatsOutputString overzetten |
| 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 overzetten |
| Een eigenschapswaarde instellen | myObject.MyProperty = value; |
myObject.MyProperty(value); |
|
| Een eigenschapswaarde verhogen | myObject.MyProperty += v; |
myObject.MyProperty(thing.Property() + v);Gebruik voor tekenreeksen een builder |
|
| ToString() | myObject.ToString() |
winrt::to_hstring(myObject) |
ToString() |
| Taaltekenreeks naar Windows Runtime-tekenreeks | N/A | winrt::hstring{ s } |
|
| Tekenreeks bouwen | StringBuilder builder;builder.Append(...); |
std::wostringstream builder;builder << ...; |
Strings samenstellen |
| Tekenreeksinterpolatie | $"{i++}) {s.Title}" |
winrt::to_hstring en/of winrt::hstring::operator+ | De methode OnNavigatedTo overzetten |
| Lege tekenreeks voor vergelijking | System.String.Empty | winrt::hstring::empty | De methode UpdateStatus overzetten |
| 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 (exceptie genereren bij mislukking) | (MyType)v |
v.as<MyType>() |
De Footer_Click-methode overzetten |
| 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() |
Overzetten van de constructor, Current en FEATURE_NAME |
| Overschakelen naar de ui-thread | CoreDispatcher.RunAsync | DispatcherQueue.TryEnqueue, of winrt::resume_foreground | De methode NotifyUser overzetten en de methode HistoryAndRoaming overzetten |
| 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.
Opbouw van UI-elementen
Deze codevoorbeelden tonen de constructie van een UI-element in de imperatieve code van een XAML-pagina.
var myTextBlock = new TextBlock()
{
Text = "Text",
Style = (Microsoft.UI.Xaml.Style)this.Resources["MyTextBlockStyle"]
};
TextBlock myTextBlock;
myTextBlock.Text(L"Text");
myTextBlock.Style(
winrt::unbox_value<Microsoft::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. U moet overbelastingen toevoegen voor eventuele extra typen die u wilt stringifyen.
| Language | Stringify int | Enum naar tekenreeks 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); |
Als u een enum naar een tekenreeks converteert, moet u de implementatie van winrt::to_hstring aanleveren.
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 tekenreeksrepresentaties worden vaak impliciet verwerkt door gegevensbinding.
<TextBlock>
You have <Run Text="{Binding FlowerCount}"/> flowers.
</TextBlock>
<TextBlock>
Most recent status is <Run Text="{x:Bind LatestOperation.Status}"/>.
</TextBlock>
Met deze bindingen wordt winrt::to_hstring van de afhankelijke eigenschap uitgevoerd. In het tweede voorbeeld ( statusenum) moet u uw eigen overbelasting van winrt::to_hstring opgeven, anders krijgt u een compilerfout.
Zie ook De methode Footer_Click porteren.
Tekenreeks bouwen
Voor het samenstellen van tekenreeksen heeft C# een ingebouwd StringBuilder-type.
| Category | C# | C++/WinRT |
|---|---|---|
| Tekenreeks bouwen | StringBuilder builder;builder.Append(...); |
std::wostringstream builder;builder << ...; |
| Een Windows Runtime-tekenreeks toevoegen, waarbij null-tekens behouden blijven | 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 de methode BuildClipboardFormatsOutputString overzetten en de methode DisplayChangedFormats overzetten.
Code uitvoeren op de hoofd-UI-thread
Dit voorbeeld wordt genomen uit het voorbeeld van de streepjescodescanner.
Als u wilt werken aan de hoofd-UI-thread in een C#-project, gebruikt u doorgaans de methode DispatcherQueue.TryEnqueue (of de oudere CoreDispatcher.RunAsync in UWP). Het patroon ziet er als volgt uit in C#.
private async void Watcher_Added(DeviceWatcher sender, DeviceInformation args)
{
DispatcherQueue.TryEnqueue(() =>
{
// Do work on the main UI thread here.
});
}
Het is veel eenvoudiger om dat in C++/WinRT uit te drukken. Merk op dat we parameters op basis van waarde doorgeven, ervan uitgaande dat we er na het eerste onderbrekingspunt toegang toe willen hebben (de co_await, in dit geval). Zie Parameter-passing voor meer informatie.
winrt::fire_and_forget Watcher_Added(DeviceWatcher sender, winrt::DeviceInformation args)
{
co_await DispatcherQueue();
// Do work on the main UI thread here.
}
Als u het werk met een andere prioriteit dan de standaardprioriteit moet uitvoeren, raadpleegt u de functie winrt::resume_foreground, die een overload heeft die een prioriteit accepteert. Zie Programmeren met threadaffiniteit in gedachten voor codevoorbeelden die laten zien hoe u wacht op een aanroep naar winrt::resume_foreground.
Taken met betrekking tot het overzetten die specifiek zijn voor C++/WinRT
Runtimeklassen definiëren in IDL
Zie IDL voor het type MainPage en voeg uw .idl bestanden samen.
Neem de C++/WinRT-Windows naamruimteheaderbestanden op die u nodig hebt
Wanneer u in C++/WinRT een type uit een Windows naamruimten wilt gebruiken, moet u het bijbehorende C++/WinRT-Windows naamruimteheaderbestand opnemen. Zie De methode NotifyUser overzetten voor een voorbeeld.
Verpakken en uitpakken
C# vakken automatisch scalaire waarden in objecten. C++/WinRT vereist dat u de winrt::box_value-functie expliciet aanroept. Voor beide talen moet u het selectievakje expliciet uitvinken. Zie Boksen 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; |
| Operation | 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# werpen een uitzondering op als u probeert een null-pointer te unboxen naar een waardetype. 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.
| Scenario | C# | C++/WinRT |
|---|---|---|
| Een bekend geheel getal uitpakken | i = (int)o; |
i = unbox_value<int>(o); |
| Als o null is | System.NullReferenceException |
Ongeluk |
| Als o geen geboxte int is | System.InvalidCastException |
Ongeluk |
| Pak int uit, gebruik de fallback als deze null is; crash in alle andere gevallen | i = o != null ? (int)o : fallback; |
i = o ? unbox_value<int>(o) : fallback; |
| Unbox int indien mogelijk; gebruik anders een fallback voor alle andere gevallen | i = as int? ?? fallback; |
i = unbox_value_or<int>(o, fallback); |
Zie voor een voorbeeld de methode OnNavigatedTo overzetten en de methode Footer_Click overzetten.
Boxing en unboxing van een tekenreeks
Een tekenreeks is in sommige opzichten een waardetype en in andere opzichten een referentietype. C# en C++/WinRT behandelen tekenreeksen anders.
Het ABI-type HSTRING is een aanwijzer naar een tekenreeks die wordt geteld. Maar het is niet afgeleid van IInspectable, dus het is technisch geen object. Bovendien vertegenwoordigt een null-HSTRING de lege tekenreeks. Boksen van dingen die niet zijn afgeleid van IInspectable wordt uitgevoerd door ze in een IReference<T> te verpakken en de Windows Runtime biedt een standaard implementatie 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.
| Behavior | C# | C++/WinRT |
|---|---|---|
| Verklaringen | object o;string s; |
IInspectable o;hstring s; |
| Categorie van het tekenreekstype | Verwijzingstype | Waardetype |
| null HSTRING projecteert als | "" |
hstring{} |
Zijn null en "" identiek? |
No | Yes |
| 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 een object toewijst |
o = "";o != null |
o = box_value(hstring{L""});o != nullptr |
Basisprincipes van boxing en unboxing.
| Operation | C# | C++/WinRT |
|---|---|---|
| Plaats een kader om een tekenreeks | o = s;Een lege tekenreeks wordt een object dat niet null is. |
o = box_value(s);Een lege tekenreeks wordt een object dat niet null is. |
| Een bekende tekenreeks uitpakken | s = (string)o;Null-object wordt null-tekenreeks. InvalidCastException als het geen string 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. OR s = o as string ?? fallback;Null of niet-tekenreeks wordt terugval. De lege tekenreeks is behouden. |
s = unbox_value_or<hstring>(o, fallback);Null of niet-tekenreeks wordt terugval. De lege tekenreeks is behouden. |
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-opmaak gebruiken
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 -markeringsextensie {x:Bind} openbaar worden weergegeven in IDL.
Ook wordt bij binding aan een Booleaanse waarde in C# true of false weergegeven, maar in C++/WinRT wordt Windows.Foundation.IReference`1<Boolean> weergegeven.
Zie Objecten in markup gebruiken voor meer informatie en codevoorbeelden.
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 zowel IObservableVectorT< als IObservableVector ><IInspectable> ondersteunt. Zie De eigenschap Scenario's overzetten voor een voorbeeld.
U kunt uw Midl-bestand (.idl) als volgt opstellen (zie ook Runtime-klassen onderbrengen in Midl-bestanden (.idl)).
namespace Bookstore
{
runtimeclass BookSku { ... }
runtimeclass BookstoreViewModel
{
Windows.Foundation.Collections.IObservableVector<BookSku> BookSkus{ get; };
}
runtimeclass MainPage : Microsoft.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 besturingselementen voor XAML-items voor meer informatie; bind aan een C++/WinRT-verzameling en 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 (zal over elementen itereren en deze opslaan in een privécollectie)
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 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<T implementeert, IEnumerable T> automatisch IEnumerable implementeert. Op ABI-niveau betekent dit dat elk object dat IObservableVector T< implementeert, 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 is opgegeven.
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 implementatie.
// 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 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;
}
Afgeleide klassen
Om van een runtime-klasse te kunnen overerven, moet de basisklasse samenstelbaar zijn. C# vereist niet dat u speciale stappen uitvoert om uw klassen composable te maken, maar C++/WinRT wel. U gebruikt het niet-verzegelde trefwoord om aan te geven dat uw klasse bruikbaar moet zijn als basisklasse.
unsealed runtimeclass BasePage : Microsoft.UI.Xaml.Controls.Page
{
...
}
runtimeclass DerivedPage : BasePage
{
...
}
In het headerbestand voor uw implementatietype moet 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>
{
...
}
}
Belangrijke API's
Verwante onderwerpen
Windows developer