Umstellen von C# auf C++/WinRTMove to C++/WinRT from C#

Dieses Thema enthält einen umfassenden Katalog der technischen Details der Portierung des Quellcodes in einem C#-Projekt zum entsprechenden Äquivalent in C++/WinRT-.This topic comprehensively catalogs the technical details involved in porting the source code in a C# project to its equivalent in C++/WinRT.

Eine Fallstudie zum Portieren eines der App-Beispiele für die universelle Windows-Plattform (UWP) finden Sie im Begleitthema Portieren des Beispiels „Zwischenablage“ (Clipboard) von C# zu C++/WinRT.For a case study of porting one of the Universal Windows Platform (UWP) app samples, see the companion topic Porting the Clipboard sample to C++/WinRT from C#. Sie können Praxis und Erfahrung mit dem Portieren sammeln, indem Sie der exemplarischen Vorgehensweise folgen und in deren Verlauf das Beispiel für sich selbst portieren.You can gain porting practice and experience by following along with that walkthrough, and porting the sample for yourself as you go.

Wie Sie sich vorbereiten und was Sie erwarten dürfenHow to prepare, and what to expect

Die Fallstudie Portieren des Beispiels „Zwischenablage“ (Clipboard) von C# zu C++/WinRT veranschaulicht Beispiele der Arten von Softwareentwurfsentscheidungen, die Sie beim Portieren eines Projekts zu C++/WinRT treffen.The case study Porting the Clipboard sample to C++/WinRT from C# illustrates examples of the kinds of software design decisions that you'll make while porting a project to C++/WinRT. Es ist also eine gute Idee, sich auf die Portierung vorzubereiten, indem man sich ein solides Verständnis davon verschafft, wie der vorhandene Code funktioniert.So, it's a good idea to prepare for porting by gaining a solid understanding of how the existing code works. Auf diese Weise erhalten Sie einen guten Überblick über die Funktionen der App und die Struktur des Codes, und die Entscheidungen, die Sie treffen, werden Sie stets vorwärts und in die richtige Richtung bringen.That way, you'll get a good overview of the app's functionality, and the code's structure, and then the decisions that you make will always take you forward, and in the right direction.

Die Arten der zu erwartenden Portierungsänderungen lassen sich in vier Kategorien gruppieren.In terms of what kinds of porting changes to expect, you could group them into four categories.

  • Portieren der Sprachprojektion.Port the language projection. Die Windows-Runtime (WinRT) wird in verschiedene Programmiersprachen projiziert.The Windows Runtime (WinRT) is projected into various programming languages. Jede dieser Sprachprojektionen ist so konzipiert, dass sie idiomatisch an die betreffende Programmiersprache angepasst ist.Each of those language projections is designed to feel idiomatic to the programming language in question. Für C# werden einige Windows-Runtime-Typen als .NET-Typen projiziert.For C#, some Windows Runtime types are projected as .NET types. So wird System.Collections.Generic.IReadOnlyList<T> beispielsweise zurück zu Windows.Foundation.Collections.IVectorView<T> übersetzt.So for example you'll be translating System.Collections.Generic.IReadOnlyList<T> back to Windows.Foundation.Collections.IVectorView<T>. Ebenfalls werden in C# einige Windows-Runtime-Operationen als praktische C#-Sprachfunktionen projiziert.Also in C#, some Windows Runtime operations are projected as convenient C# language features. In C# verwenden Sie beispielsweise die +=-Operatorsyntax zum Registrieren eines Ereignisbehandlungsdelegaten.An example is that in C# you use the += operator syntax to register an event-handling delegate. Sie übersetzen also Sprachfeatures wie diese zurück in die grundlegende Operation, die gerade ausgeführt wird (in diesem Beispiel die Ereignisregistrierung).So you'll be translating language features such as that back to the fundamental operation that's being performed (event registration, in this example).
  • Portieren der Sprachsyntax.Port language syntax. Viele dieser Änderungen sind einfache mechanische Umwandlungen, bei denen ein Symbol durch ein anderes ersetzt wird.Many of these changes are simple mechanical transforms, replacing one symbol for another. Zum Beispiel wird ein Punkt (.) in einen Doppelpunkt (::) geändert.For example, changing dot (.) to double-colon (::).
  • Portieren von Sprachprozeduren.Port language procedure. Einige davon können einfache, sich wiederholende Änderungen sein (wie z. B. myObject.MyProperty in myObject.MyProperty()).Some of these can be simple, repetitive changes (such as myObject.MyProperty to myObject.MyProperty()). Andere benötigen tiefer gehende Änderungen (z. B. die Portierung einer Prozedur, die die Verwendung von System.Text.StringBuilder beinhaltet, in eine Prozedur, die die Verwendung von std::wostringstream beinhaltet).Others need deeper changes (for example, porting a procedure that involves the use of System.Text.StringBuilder to one that involves the use of std::wostringstream).
  • Portieren zugehöriger Tasks, die spezifisch für C++/WinRT sind.Porting-related tasks that are specific to C++/WinRT. Bestimmte Details der Windows-Runtime werden von C# implizit im Hintergrund erledigt.Certain details of the Windows Runtime are taken care of impliclicly by C#, behind the scenes. Diese Details werden explizit in C++/WinRT durchgeführt.Those details are done explicitly in C++/WinRT. Ein Beispiel ist die Verwendung einer .idl-Datei, um Ihre Laufzeitklassen zu definieren.An example is that you use an .idl file to define your runtime classes.

Der Rest dieses Themas ist nach dieser Taxonomie gegliedert.The rest of this topic is structured according to that taxonomy.

Änderungen, die die Sprachprojektion betreffenChanges that involve the language projection

CategoryCategory C#C# C++/WinRTC++/WinRT Siehe auchSee also
Nicht typisiertes ObjektUntyped object object oder System.Objectobject, or System.Object Windows::Foundation::IInspectableWindows::Foundation::IInspectable Portieren der EnableClipboardContentChangedNotifications-MethodePorting the EnableClipboardContentChangedNotifications method
ProjektionsnamespacesProjection namespaces using System; using namespace Windows::Foundation;
using System.Collections.Generic; using namespace Windows::Foundation::Collections;
Größe einer SammlungSize of a collection collection.Count collection.Size() Portieren der BuildClipboardFormatsOutputString-MethodePorting the BuildClipboardFormatsOutputString method
Typischer SammlungstypTypical collection type IList<T> und Hinzufügen, um ein Element hinzuzufügen.IList<T>, and Add to add an element. IVector<T> und Anfügen, um ein Element hinzuzufügen.IVector<T>, and Append to add an element. Wenn Sie an einer beliebigen Stelle einen std::vector verwenden, führen Sie ein push_back aus, um ein Element hinzuzufügen.If you use a std::vector anywhere, then push_back to add an element.
Schreibgeschützter SammlungstypRead-only collection type IReadOnlyList<T> IReadOnlyList<T> IVectorView<T> IVectorView<T> Portieren der BuildClipboardFormatsOutputString-MethodePorting the BuildClipboardFormatsOutputString method
Ereignishandlerdelegat als KlassenmemberEvent handler delegate as class member myObject.EventName += Handler; token = myObject.EventName({ get_weak(), &Class::Handler }); Portieren der EnableClipboardContentChangedNotifications-MethodePorting the EnableClipboardContentChangedNotifications method
Ereignishandlerdelegat widerrufenRevoke event handler delegate myObject.EventName -= Handler; myObject.EventName(token); Portieren der EnableClipboardContentChangedNotifications-MethodePorting the EnableClipboardContentChangedNotifications method
Assoziativer ContainerAssociative container IDictionary<K, V> IDictionary<K, V> IMap<K, V> IMap<K, V>
VektormemberzugriffVector member access x = v[i];
v[i] = x;
x = v.GetAt(i);
v.SetAt(i, x);

Registrieren/Widerrufen eines EreignishandlersRegister/revoke an event handler

In C++/WinRT haben Sie mehrere syntaktische Optionen, um einen Ereignishandlerdelegaten zu registrieren/widerrufen, wie in Behandeln von Ereignissen mithilfe von Delegaten in C++/WinRT beschrieben.In C++/WinRT, you have several syntactic options to register/revoke an event handler delegate, as described in Handle events by using delegates in C++/WinRT. Siehe auch Portieren der EnableClipboardContentChangedNotifications-Methode.Also see Porting the EnableClipboardContentChangedNotifications method.

Manchmal, z. B. wenn ein Ereignisempfänger (ein Objekt, das ein Ereignis behandelt) kurz vor der Zerstörung steht, möchten Sie einen Ereignishandler vielleicht widerrufen, damit die Ereignisquelle (das Objekt, das das Ereignis auslöst) kein zerstörtes Objekt aufruft.Sometimes, for example when an event recipient (an object handling an event) is about to be destroyed, you'll want to revoke an event handler so that the event source (the object raising the event) doesn't call into a destroyed object. Mehr dazu erfahren Sie unter Einen registrierten Delegaten widerrufen.See Revoke a registered delegate. Erstellen Sie in solchen Fällen eine event_token-Membervariable für Ihre Ereignishandler.In cases like that, create an event_token member variable for your event handlers. Siehe z. B. Portieren der EnableClipboardContentChangedNotifications-Methode.For an example, see Porting the EnableClipboardContentChangedNotifications method.

Ein Ereignishandler kann auch in XAML-Markup registriert werden.You can also register an event handler in XAML markup.

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

In C# kann deine OpenButton_Click-Methode privat sein, und XAML kann sie trotzdem mit dem ButtonBase.Click-Ereignis verbinden, das von OpenButton ausgelöst wird.In C#, your OpenButton_Click method can be private, and XAML will still be able to connect it to the ButtonBase.Click event raised by OpenButton.

In C++/WinRT muss deine OpenButton_Click-Methode in deinem Implementierungstyp öffentlich sein, wenn du sie in XAML-Markup registrieren möchtest.In C++/WinRT, your OpenButton_Click method must be public in your implementation type if you want to register it in XAML markup. Wenn du einen Ereignisbehandler nur in imperativem Code registrierst, dann muss der Ereignishandler nicht öffentlich sein.If you register an event handler only in imperative code, then the event handler doesn't need to be public.

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

Alternativ dazu kannst du die registrierende XAML-Seite als Friend deines Implementierungstyps und OpenButton_Click als privat festlegen.Alternatively, you can make the registering XAML page a friend of your implementation type, and OpenButton_Click private.

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);
    }
};

Ein letztes Szenario ist eines, in dem das C#-Projekt, das Sie portieren, vom Markup aus an den Ereignishandler gebunden wird (mehr Hintergrund zu diesem Szenario finden Sie unter Funktionen in x:Bind).One final scenario is where the C# project that you're porting binds to the event handler from markup (for more background on that scenario, see Functions in x:Bind).

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

Sie können dieses Markup einfach in das einfachere Click="OpenButton_Click" ändern.You could just change that markup to the more simple Click="OpenButton_Click". Oder wenn Sie es bevorzugen, können Sie dieses Markup unverändert verwenden.Or, if you prefer, you can keep that markup as it is. Um dieses Verfahren zu unterstützen, brauchen Sie lediglich den Ereignisbehandler in IDL zu deklarieren.All you have to do to support it is to declare the event handler in IDL.

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

Hinweis

Deklarieren Sie die Funktion als void, auch wenn Sie sie als Fire and Forget (Auslösen und Vergessen) implementieren.Declare the function as void even if you implement it as Fire and forget.

Änderungen, die die Sprachsyntax betreffenChanges that involve the language syntax

CategoryCategory C#C# C++/WinRTC++/WinRT Siehe auchSee also
ZugriffsmodifiziererAccess modifiers public \<member\> public:
    \<member\>
Portieren der Button_Click-MethodePorting the Button_Click method
Auf ein Datenmember zugreifenAccess a data member this.variable this->variable
Asynchrone AktionAsync action async Task ... IAsyncAction ...
Asynchroner VorgangAsync operation async Task<T> ... IAsyncOperation<T> ...
Fire-and-Forget-Methode (impliziert „Asynchron“)Fire-and-forget method (implies async) async void ... winrt::fire_and_forget ... Portieren der CopyButton_Click-MethodePorting the CopyButton_Click method
Zugriff auf eine EnumerationskonstanteAccess an enumerated constant E.Value E::Value Portieren der DisplayChangedFormats-MethodePorting the DisplayChangedFormats method
Kooperatives WaitCooperatively wait await ... co_await ... Portieren der CopyButton_Click-MethodePorting the CopyButton_Click method
Sammlung von projizierten Typen als privates FeldCollection of projected types as a private field private List<MyRuntimeClass> myRuntimeClasses = new List<MyRuntimeClass>(); std::vector
<MyNamespace::MyRuntimeClass>
m_myRuntimeClasses;
GUID-KonstruktionGUID construction 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} };
NamespacetrennzeichenNamespace separator A.B.T A::B::T
NullNull null nullptr Portieren der UpdateStatus-MethodePorting the UpdateStatus method
Abrufen eines TypobjektsObtain a type object typeof(MyType) winrt::xaml_typename<MyType>() Portieren der Scenarios-EigenschaftPorting the Scenarios property
Parameterdeklaration für eine MethodeParameter declaration for a method MyType MyType const& ParameterübergabeParameter-passing
Parameterdeklaration für eine asynchrone MethodeParameter declaration for an async method MyType MyType ParameterübergabeParameter-passing
Statische Methode aufrufenCall a static method T.Method() T::Method()
ZeichenfolgenStrings string oder System.Stringstring, or System.String winrt::hstringwinrt::hstring Verarbeitung von Zeichenfolgen in C++/WinRTString handling in C++/WinRT
ZeichenfolgenliteralString literal "a string literal" L"a string literal" Portieren des Konstruktors, Current und FEATURE_NAMEPorting the constructor, Current, and FEATURE_NAME
Hergeleiteter (oder abgeleiteter) TypInferred (or deduced) type var auto Portieren der BuildClipboardFormatsOutputString-MethodePorting the BuildClipboardFormatsOutputString method
Using-directiveUsing-directive using A.B.C; using namespace A::B::C; Portieren des Konstruktors, Current und FEATURE_NAMEPorting the constructor, Current, and FEATURE_NAME
Ausführliche Zeichenfolgeliterale/RohzeichenfolgenliteraleVerbatim/raw string literal @"verbatim string literal" LR"(raw string literal)" Portieren der DisplayToast-MethodePorting the DisplayToast method

Hinweis

Wenn eine Header Datei keine using namespace-Direktive für einen bestimmten Namespace enthält, müssen Sie alle Typnamen für diesen Namespace vollständig qualifizieren oder zumindest ausreichend qualifizieren, damit der Compiler Sie finden kann.If a header file doesn't contain a using namespace directive for a given namespace, then you'll have to fully-qualify all type names for that namespace; or at least qualify them sufficiently for the compiler to find them. Ein Beispiel finden Sie unter Portieren der DisplayToast-Methode.For an example, see Porting the DisplayToast method.

Portieren von Klassen und MembernPorting classes and members

Sie müssen für jeden C#-Typ entscheiden, ob er in einen Windows-Runtime-Typ oder eine reguläre C++-Klasse/-Struktur/-Enumeration portiert werden soll.You'll need to decide, for each C# type, whether to port it to a Windows Runtime type, or to a regular C++ class/struct/enumeration. Weitere Informationen und ausführliche Beispiele, die veranschaulichen, wie Sie diese Entscheidungen treffen, finden Sie unter Portieren des Beispiels „Zwischenablage“ (Clipboard) von C# zu C++/WinRT.For more info, and detailed examples illustrating how to make those decisions, see Porting the Clipboard sample to C++/WinRT from C#.

Eine C#-Eigenschaft wird in der Regel zu einer Accessorfunktion, einer Mutatorfunktion und einem Unterstützungsdatenmember.A C# property typically becomes an accessor function, a mutator function, and a backing data member. Weitere Informationen und ein Beispiel finden Sie unter Portieren der IsClipboardContentChangedEnabled- -Eigenschaft.For more info, and an example, see Porting the IsClipboardContentChangedEnabled property.

Legen Sie nicht statische Felder als Datenmember Ihres Implementierungstyps fest.For non-static fields, make them data members of your implementation type.

Ein statisches C#-Feld wird zu einer statischen C++/WinRT-Accessor- und/oder Mutatorfunktion.A C# static field becomes a C++/WinRT static accessor and/or mutator function. Weitere Informationen und ein Beispiel finden Sie unter Portieren des Konstruktors, Current und FEATURE_NAME.For more info, and an example, see Porting the constructor, Current, and FEATURE_NAME.

Auch für jede einzelne Memberfunktion müssen Sie sich entscheiden, ob sie in die IDL gehört, oder ob es sich um eine öffentliche oder private Memberfunktion Ihres Implementierungstyps handelt.For member functions, again, you'll need to decide for each one whether or not it belongs in the IDL, or whether it's a public or private member function of your implementation type. Weitere Informationen und Beispiele zur Entscheidungsfindung finden Sie unter IDL für den MainPage-Typ.For more info, and examples of how to decide, see IDL for the MainPage type.

Portieren von XAML-Markup- und RessourcendateienPorting XAML markup, and asset files

Im Falle von Portieren des Beispiels „Zwischenablage“ (Clipboard) von C# zu C++/WinRT können wir über das C#- und das C++/WinRT-Projekt hinweg das gleiche XAML-Markup (einschließlich der Ressourcen) und die gleichen Ressourcendateien verwenden.In the case of Porting the Clipboard sample to C++/WinRT from C#, we were able to use the same XAML markup (including resources) and asset files across the C# and the C++/WinRT project. In einigen Fällen sind Änderungen an Markup erforderlich, um dies zu erreichen.In some cases, edits to markup will be necessary to achieve that. Siehe Kopieren von XAML und Stilen, die notwendig sind, um das Portieren von MainPage abzuschließen.See Copy the XAML and styles necessary to finish up porting MainPage.

Änderungen, die Prozeduren in der Sprache betreffenChanges that involve procedures within the language

CategoryCategory C#C# C++/WinRTC++/WinRT Siehe auchSee also
Verwaltung der Lebensdauer in einer asynchronen MethodeLifetime management in an async method NICHT ZUTREFFENDN/A auto lifetime{ get_strong() }; oderauto lifetime{ get_strong() }; or
auto lifetime = get_strong();
Portieren der CopyButton_Click-MethodePorting the CopyButton_Click method
VerwerfenDisposal using (var t = v) auto t{ v };
t.Close(); // or let wrapper destructor do the work
Portieren der CopyImage-MethodePorting the CopyImage method
Objekt erstellenConstruct object new MyType(args) MyType{ args } oderMyType{ args } or
MyType(args)
Portieren der Scenarios-EigenschaftPorting the Scenarios property
Nicht initialisierten Verweis erstellenCreate uninitialized reference MyType myObject; MyType myObject{ nullptr }; oderMyType myObject{ nullptr }; or
MyType myObject = nullptr;
Portieren des Konstruktors, Current und FEATURE_NAMEPorting the constructor, Current, and FEATURE_NAME
Objekt in Variable mit Argumenten erstellenConstruct object into variable with args var myObject = new MyType(args); auto myObject{ MyType{ args } }; oderauto myObject{ MyType{ args } }; or
auto myObject{ MyType(args) }; oderauto myObject{ MyType(args) }; or
auto myObject = MyType{ args }; oderauto myObject = MyType{ args }; or
auto myObject = MyType(args); oderauto myObject = MyType(args); or
MyType myObject{ args }; oderMyType myObject{ args }; or
MyType myObject(args);
Portieren der Footer_Click-MethodePorting the Footer_Click method
Objekt in Variable ohne Argumente erstellenConstruct object into variable without args var myObject = new T(); MyType myObject; Portieren der BuildClipboardFormatsOutputString-MethodePorting the BuildClipboardFormatsOutputString method
Objektinitialisierung (kompakt)Object initialization shorthand var p = new FileOpenPicker{
    ViewMode = PickerViewMode.List
};
FileOpenPicker p;
p.ViewMode(PickerViewMode::List);
MassenvektorvorgangBulk vector operation var p = new FileOpenPicker{
    FileTypeFilter = { ".png", ".jpg", ".gif" }
};
FileOpenPicker p;
p.FileTypeFilter().ReplaceAll({ L".png", L".jpg", L".gif" });
Portieren der CopyButton_Click-MethodePorting the CopyButton_Click method
Sammlung durchlaufenIterate over collection foreach (var v in c) for (auto&& v : c) Portieren der BuildClipboardFormatsOutputString-MethodePorting the BuildClipboardFormatsOutputString method
Ausnahme abfangenCatch an exception catch (Exception ex) catch (winrt::hresult_error const& ex) Portieren der PasteButton_Click-MethodePorting the PasteButton_Click method
AusnahmedetailsException details ex.Message ex.message() Portieren der PasteButton_Click-MethodePorting the PasteButton_Click method
Eigenschaftswert abrufenGet a property value myObject.MyProperty myObject.MyProperty() Portieren der notifyuser-MethodePorting the NotifyUser method
Eigenschaftswert festlegenSet a property value myObject.MyProperty = value; myObject.MyProperty(value);
Eigenschaftswert schrittweise erhöhenIncrement a property value myObject.MyProperty += v; myObject.MyProperty(thing.Property() + v);
Für Zeichenfolgen zu einem Generator wechselnFor strings, switch to a builder
ToString()ToString() myObject.ToString() winrt::to_hstring(myObject) ToString()ToString()
Sprachzeichenfolge in Windows-Runtime-ZeichenfolgeLanguage string to Windows Runtime string NICHT ZUTREFFENDN/A winrt::hstring{ s }
Erstellung von string-ElementenString-building StringBuilder builder;
builder.Append(...);
std::wostringstream builder;
builder << ...;
Erstellung von string-ElementenString-building
ZeichenfolgeninterpolierungString interpolation $"{i++}) {s.Title}" winrt::to_hstring und/oder winrt::hstring::operator+ winrt::to_hstring, and/or winrt::hstring::operator+ Portieren der OnNavigatedTo-MethodePorting the OnNavigatedTo method
Leere Zeichenfolge für den VergleichEmpty string for comparison System.String.EmptySystem.String.Empty winrt::hstring::emptywinrt::hstring::empty Portieren der UpdateStatus-MethodePorting the UpdateStatus method
Erstellen einer leeren ZeichenfolgeCreate empty string var myEmptyString = String.Empty; winrt::hstring myEmptyString{ L"" };
WörterbuchvorgängeDictionary operations map[k] = v; // replaces any existing
v = map[k]; // throws if not present
map.ContainsKey(k)
map.Insert(k, v); // replaces any existing
v = map.Lookup(k); // throws if not present
map.HasKey(k)
Typkonvertierung (bei Fehler auslösen)Type conversion (throw on failure) (MyType)v v.as<MyType>() Portieren der Footer_Click-MethodePorting the Footer_Click method
Typkonvertierung (bei Fehler auf „Null“ festlegen)Type conversion (null on failure) v as MyType v.try_as<MyType>() Portieren der PasteButton_Click-MethodePorting the PasteButton_Click method
XAML-Elemente mit „x:Name“ sind Eigenschaften.XAML elements with x:Name are properties MyNamedElement MyNamedElement() Portieren des Konstruktors, Current und FEATURE_NAMEPorting the constructor, Current, and FEATURE_NAME
Zum UI-Thread wechselnSwitch to the UI thread CoreDispatcher.RunAsyncCoreDispatcher.RunAsync CoreDispatcher.RunAsync oder winrt::resume_foregroundCoreDispatcher.RunAsync, or winrt::resume_foreground Portieren der NotifyUser-Methode und Portieren der HistoryAndRoaming-MethodePorting the NotifyUser method, and Porting the HistoryAndRoaming method
Erstellung von Benutzeroberflächenelementen in imperativem Code auf einer XAML-SeiteUI element construction in imperative code in a XAML page Siehe Erstellen von BenutzeroberflächenelementenSee UI element construction Siehe Erstellen von BenutzeroberflächenelementenSee UI element construction

In den folgenden Abschnitten finden Sie ausführliche Informationen zu einigen Elementen in der Tabelle.The following sections go into more detail regarding some of the items in the table.

Erstellen von BenutzeroberflächenelementenUI element construction

Diese Codebeispiele veranschaulichen die Erstellung eines Benutzeroberflächenelements im imperativen Code einer XAML-Seite.These code examples show the construction of a UI element in the imperative code of a XAML page.

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()ToString()

C#-Typen stellen die Object.ToString-Methode bereit.C# types provide the Object.ToString method.

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

In C++/WinRT ist dies nicht direkt verfügbar, aber du kannst Alternativen nutzen.C++/WinRT doesn't directly provide this facility, but you can turn to alternatives.

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

C++/WinRT unterstützt auch winrt::to_hstring für eine begrenzte Anzahl von Typen.C++/WinRT also supports winrt::to_hstring for a limited number of types. Du musst Überladungen für alle zusätzlichen Typen hinzufügen, für die du eine Stringification durchführen möchtest.You'll need to add overloads for any additional types you want to stringify.

LanguageLanguage Stringification von „int“Stringify int Stringification von „enum“Stringify enum
C#C# string result = "hello, " + intValue.ToString();
string result = $"hello, {intValue}";
string result = "status: " + status.ToString();
string result = $"status: {status}";
C++/WinRTC++/WinRT hstring result = L"hello, " + to_hstring(intValue); // must define overload (see below)
hstring result = L"status: " + to_hstring(status);

Bei der Stringification eines enum-Typs musst du die Implementierung von winrt::to_hstring bereitstellen.In the case of stringifying an enum, you will need to provide the implementation of 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));
        }
    }
}

Diese Stringifications werden häufig implizit von der Datenbindung verwendet.These stringifications are often consumed implicitly by data binding.

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

Diese Bindungen führen winrt::to_hstring der gebundenen Eigenschaft durch.These bindings will perform winrt::to_hstring of the bound property. Im zweiten Beispiel (StatusEnum) musst du eine eigene Überladung von winrt::to_hstring bereitstellen, andernfalls erhältst du einen Compilerfehler.In the case of the second example (the StatusEnum), you must provide your own overload of winrt::to_hstring, otherwise you'll get a compiler error.

Siehe auch Portieren der Footer_Click-Methode.Also see Porting the Footer_Click method.

Erstellung von string-ElementenString-building

Für die Erstellung von string-Elementen verfügt C# über einen integrierten StringBuilder-Typ.For string building, C# has a built-in StringBuilder type.

CategoryCategory C#C# C++/WinRTC++/WinRT
Erstellung von string-ElementenString-building StringBuilder builder;
builder.Append(...);
std::wostringstream builder;
builder << ...;
Anfügen einer Windows-Runtime-Zeichenfolge unter Beibehalten von NULL-WertenAppend a Windows Runtime string, preserving nulls builder.Append(s); builder << std::wstring_view{ s };
Neue Zeile hinzufügenAdd a newline builder.Append(Environment.NewLine); builder << std::endl;
Auf das Ergebnis zugreifenAccess the result s = builder.ToString(); ws = builder.str();

Weitere Informationen finden Sie auch unter Portieren der BuildClipboardFormatsOutputString-Methode und Portieren der DisplayChangedFormats-Methode.Also see Porting the BuildClipboardFormatsOutputString method, and Porting the DisplayChangedFormats method.

Ausführen von Code im Haupt-UI-ThreadRunning code on the main UI thread

Dieses Beispiel stammt aus dem Barcodescanner-Beispiel.This example is taken from the Barcode scanner sample.

Wenn Sie am Haupt-UI-Thread in einem C#-Projekt arbeiten möchten, verwenden Sie normalerweise die Methode CoreDispatcher.RunAsync wie hier.When you want to do work on the main UI thread in a C# project, you typically use the CoreDispatcher.RunAsync method, like this.

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

Es ist viel einfacher, das in C++/WinRT auszudrücken.It's much simpler to express that in C++/WinRT. Beachten Sie, dass Parameter nach Wert akzeptiert werden, unter der Annahme, dass nach dem ersten Anhaltepunkt (in diesem Fall dem co_await) darauf zugegriffen werden soll.Notice that we're accepting parameters by value on the assumption we'll want to access them after the first suspension point (the co_await, in this case). Weitere Informationen finden Sie unter Parameterübergabe.For more info, see Parameter-passing.

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

Wenn Sie die Arbeit mit einer anderen Priorität als der Standardpriorität ausführen müssen, sehen Sie sich die Funktion winrt::resume_foreground an, die eine Überladung aufweist, die Priorität erfordert.If you need to do the work at a priority other than the default, then see the winrt::resume_foreground function, which has an overload that takes a priority. Codebeispiele, die zeigen, wie ein Aufruf von winrt::resume_foreground abgewartet werden kann, finden Sie unter Programmieren mit Threadaffinität.For code examples showing how to await a call to winrt::resume_foreground, see Programming with thread affinity in mind.

Definieren Ihrer Laufzeitklassen in IDLDefine your runtime classes in IDL

Weitere Informationen finden Sie unter IDL für den MainPage-Typ und Konsolidieren Ihrer .idl-Dateien.See IDL for the MainPage type, and Consolidate your .idl files.

Schließen Sie die erforderlichen C++/WinRT-Headerdateien des Windows-Namespace ein.Include the C++/WinRT Windows namespace header files that you need

Wann immer Sie in C++/WinRT einen Typ aus einem Windows-Namespace verwenden möchten, müssen Sie die entsprechende C++/WinRT-Windows-Namespace-Headerdatei einschließen.In C++/WinRT, whenever you want to use a type from a Windows namespaces, you need to include the corresponding C++/WinRT Windows namespace header file. Ein Beispiel finden Sie unter Portieren der NotifyUser-Methode.For an example, see Porting the NotifyUser method.

Boxing und UnboxingBoxing and unboxing

C# führt automatisch ein Boxing von Skalaren zu Objekten durch.C# automatically boxes scalars into objects. In C++/WinRT musst du die Funktion winrt::box_value explizit aufrufen.C++/WinRT requires you to call the winrt::box_value function explicitly. In beiden Sprachen musst du ein Unboxing explizit angeben.Both languages require you to unbox explicitly. Siehe Boxing und Unboxing mit C++/WinRT.See Boxing and unboxing with C++/WinRT.

In der unten stehenden Tabelle werden folgende Definitionen verwendet.In the tables that follows, we'll use these definitions.

C#C# C++/WinRTC++/WinRT
int i; int i;
string s; winrt::hstring s;
object o; IInspectable o;
VorgangOperation C#C# C++/WinRTC++/WinRT
BoxingBoxing o = 1;
o = "string";
o = box_value(1);
o = box_value(L"string");
UnboxingUnboxing i = (int)o;
s = (string)o;
i = unbox_value<int>(o);
s = unbox_value<winrt::hstring>(o);

C++/CX und C# lösen Ausnahmen aus, wenn du versuchst, ein Unboxing eines NULL-Zeigers auf einen Werttyp auszuführen.C++/CX and C# raise exceptions if you try to unbox a null pointer to a value type. C++/WinRT betrachtet dies als Programmierfehler und stürzt ab.C++/WinRT considers this a programming error, and it crashes. Verwende in C++/WinRT die Funktion winrt::unbox_value_or, wenn ein Objekt nicht den von dir angenommenen Typ aufweist.In C++/WinRT, use the winrt::unbox_value_or function if you want to handle the case where the object is not of the type that you thought it was.

SzenarioScenario C#C# C++/WinRTC++/WinRT
Unboxing eines bekannten integer-ElementsUnbox a known integer i = (int)o; i = unbox_value<int>(o);
Wenn „o“ NULL istIf o is null System.NullReferenceException AbsturzCrash
Wenn „o“ kein geboxter int-Wert istIf o is not a boxed int System.InvalidCastException AbsturzCrash
Unboxing für „int“, Fallback bei NULL; Absturz in allen anderen FällenUnbox int, use fallback if null; crash if anything else i = o != null ? (int)o : fallback; i = o ? unbox_value<int>(o) : fallback;
Unboxing für „int“ (falls möglich); Fallback in allen anderen FällenUnbox int if possible; use fallback for anything else i = as int? ?? fallback; i = unbox_value_or<int>(o, fallback);

Ein Beispiel finden Sie unter Portieren der OnNavigatedTo-Methode und Portieren der Footer_Click-Methode.For an example, see Porting the OnNavigatedTo method, and Porting the Footer_Click method.

Boxing und Unboxing von string-ElementenBoxing and unboxing a string

Ein string-Element ist in einigen Fällen ein Werttyp, in anderen Fällen ein Verweistyp.A string is in some ways a value type, and in other ways a reference type. C# und C++/WinRT behandeln string-Elemente unterschiedlich.C# and C++/WinRT treat strings differently.

Der ABI-Typ HSTRING ist ein Zeiger auf ein als Verweis gezähltes string-Element.The ABI type HSTRING is a pointer to a reference-counted string. Er wird jedoch nicht von IInspectable abgeleitet, ist also technisch gesehen kein Objekt.But it doesn't derive from IInspectable, so it's not technically an object. Darüber hinaus stellt ein HSTRING mit Wert NULL ein leeres string-Element dar.Furthermore, a null HSTRING represents the empty string. Das Boxing von Elementen, die nicht von IInspectable abgeleitet werden, erfolgt über den Einschluss in IReference<T> , und die Windows-Runtime stellt eine Standardimplementierung in Form des PropertyValue-Objekts bereit (benutzerdefinierte Typen werden als PropertyType::OtherType gemeldet).Boxing of things not derived from IInspectable is done by wrapping them inside an IReference<T>, and the Windows Runtime provides a standard implementation in the form of the PropertyValue object (custom types are reported as PropertyType::OtherType).

C# stellt ein string-Element der Windows-Runtime als Referenztyp dar, C++/WinRT dagegen als Werttyp.C# represents a Windows Runtime string as a reference type; while C++/WinRT projects a string as a value type. Das bedeutet, dass eine geboxte NULL-Zeichenfolge unterschiedliche Darstellungen aufweisen kann, je nachdem, wie du dorthin gelangt bist.This means that a boxed null string can have different representations depending how you got there.

VerhaltenBehavior C#C# C++/WinRTC++/WinRT
DeklarationenDeclarations object o;
string s;
IInspectable o;
hstring s;
Kategorie des string-TypsString type category VerweistypReference type WerttypValue type
HSTRING mit NULL-Wert wird dargestellt alsnull HSTRING projects as "" hstring{}
Sind NULL und "" identisch?Are null and "" identical? NeinNo JaYes
Gültigkeit von NULLValidity of null s = null;
s.Length löst NullReferenceException auss.Length raises NullReferenceException
s = hstring{};
s.size() == 0 (gültig)s.size() == 0 (valid)
Wenn Sie einem Objekt eine NULL-Zeichenfolge zuweisenIf you assign null string to object o = (string)null;
o == null
o = box_value(hstring{});
o != nullptr
Wenn Sie einem Objekt "" zuweisenIf you assign "" to object o = "";
o != null
o = box_value(hstring{L""});
o != nullptr

Grundlegendes Boxing und UnboxingBasic boxing and unboxing.

VorgangOperation C#C# C++/WinRTC++/WinRT
Boxing eines string-ElementsBox a string o = s;
Eine leere Zeichenfolge wird zu einem Nicht-NULL-Objekt.Empty string becomes non-null object.
o = box_value(s);
Eine leere Zeichenfolge wird zu einem Nicht-NULL-Objekt.Empty string becomes non-null object.
Unboxing eines bekannten string-ElementsUnbox a known string s = (string)o;
Ein NULL-Objekt wird zu einer NULL-Zeichenfolge.Null object becomes null string.
InvalidCastException, falls keine Zeichenfolge.InvalidCastException if not a string.
s = unbox_value<hstring>(o);
Absturz eines NULL-Objekts.Null object crashes.
Absturz, falls keine Zeichenfolge.Crash if not a string.
Unboxing einer möglichen ZeichenfolgeUnbox a possible string s = o as string;
Ein NULL-Objekt oder eine Nicht-Zeichenfolge wird zu einer NULL Zeichenfolge.Null object or non-string becomes null string.

oderOR

s = o as string ?? fallback;
NULL oder eine Nicht-Zeichenfolge wird zu einem Fallback.Null or non-string becomes fallback.
Leere Zeichenfolge beibehalten.Empty string preserved.
s = unbox_value_or<hstring>(o, fallback);
NULL oder eine Nicht-Zeichenfolge wird zu einem Fallback.Null or non-string becomes fallback.
Leere Zeichenfolge beibehalten.Empty string preserved.

Verfügbarmachen einer Klasse für die {Binding}-MarkuperweiterungMaking a class available to the {Binding} markup extension

Wenn du die {Binding}-Markuperweiterung zum Binden von Daten an deinen Datentyp verwenden möchtest, findest du Informationen dazu unter Mit {Binding} deklariertes Bindungsobjekt.If you intend to use the {Binding} markup extension to data bind to your data type, then see Binding object declared using {Binding}.

Verwenden von Objekten aus XAML-MarkupConsuming objects from XAML markup

In einem C#-Projekt kannst du private Member und benannte Elemente aus XAML-Markup nutzen.In a C# project, you can consume private members and named elements from XAML markup. In C++/WinRT dagegen müssen alle Entitäten, die über die XAML- {x:Bind}-Markuperweiterung genutzt werden, in IDL öffentlich verfügbar gemacht werden.But in C++/WinRT, all entities consumed by using the XAML {x:Bind} markup extension must be exposed publicly in IDL.

Durch Binden an einen booleschen Typ wird in C# true oder false angezeigt, in C++/WinRT dagegen Windows.Foundation.IReference`1<Boolean> .Also, binding to a Boolean displays true or false in C#, but it shows Windows.Foundation.IReference`1<Boolean> in C++/WinRT.

Weitere Informationen sowie Codebeispiele findest du unter Verwenden von Objekten aus Markup.For more info, and code examples, see Consuming objects from markup.

Verfügbarmachen einer Datenquelle für XAML-MarkupMaking a data source available to XAML markup

In C++/WinRT, Version 2.0.190530.8 und höher, erstellt winrt::single_threaded_observable_vector einen Observable-Vektor, der sowohl IObservableVector<T> als auch IObservableVector<IInspectable> unterstützt.In C++/WinRT version 2.0.190530.8 and higher, winrt::single_threaded_observable_vector creates an observable vector that supports both IObservableVector<T> and IObservableVector<IInspectable>. Ein Beispiel finden Sie unter Portieren der Scenarios-Eigenschaft.For an example, see Porting the Scenarios property.

Du kannst deine Midl-Datei (.idl) folgendermaßen erstellen (siehe auch Einbeziehen von Laufzeitklassen in Midl-Dateien (.idl)).You can author your Midl file (.idl) like this (also see Factoring runtime classes into Midl files (.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; };
    }
}

Die Implementierung sieht dann so aus.And implement like this.

// 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;
};
...

Weitere Informationen finden Sie unter XAML-Elementsteuerelemente: Binden an eine C++/WinRT-Sammlung und Sammlungen mit C++/WinRT.For more info, see XAML items controls; bind to a C++/WinRT collection, and Collections with C++/WinRT.

Verfügbarmachen einer Datenquelle für XAML-Markup (vor C++/WinRT 2.0.190530.8)Making a data source available to XAML markup (prior to C++/WinRT 2.0.190530.8)

Die XAML-Datenbindung erfordert, dass eine Elementquelle IIterable<IInspectable> sowie eine der folgenden Schnittstellenkombinationen implementiert.XAML data binding requires that an items source implements IIterable<IInspectable>, as well as one of the following combinations of interfaces.

  • IObservableVector<IInspectable>IObservableVector<IInspectable>
  • IBindableVector und INotifyCollectionChangedIBindableVector and INotifyCollectionChanged
  • IBindableVector und IBindableObservableVectorIBindableVector and IBindableObservableVector
  • IBindableVector allein (antwortet nicht auf Änderungen)IBindableVector by itself (will not respond to changes)
  • IVector<IInspectable>IVector<IInspectable>
  • IBindableIterable (Iteration und Speicherung von Elementen erfolgt in einer privaten Sammlung)IBindableIterable (will iterate and save elements into a private collection)

Eine generische Schnittstelle wie IVector<T> wird zur Laufzeit nicht erkannt.A generic interface such as IVector<T> can't be detected at runtime. Jede IVector<T> -Schnittstelle weist eine andere IID (Schnittstellenbezeichner) auf, die eine Funktion von T ist. Jeder Entwickler kann den T-Satz nach Belieben erweitern, daher kennt der XAML-Bindungscode nie den vollständigen Satz, der abgefragt werden muss.Each IVector<T> has a different interface identifier (IID), which is a function of T. Any developer can expand the set of T arbitrarily, so clearly the XAML binding code can never know the full set to query for. Diese Einschränkung ist kein Problem für C#, weil jedes CLR-Objekt, das IEnumerable<T> implementiert, automatisch auch IEnumerable implementiert.That restriction isn't a problem for C# because every CLR object that implements IEnumerable<T> automatically implements IEnumerable. Auf ABI-Ebene bedeutet dies, dass jedes Objekt, das IObservableVector<T> implementiert, automatisch auch IObservableVector<IInspectable> implementiert.At the ABI level, that means that every object that implements IObservableVector<T> automatically implements IObservableVector<IInspectable>.

C++/WinRT bietet diese Garantie nicht.C++/WinRT doesn't offer that guarantee. Wenn eine C++/WinRT-Laufzeitklasse IObservableVector<T> implementiert, kann nicht davon ausgegangen werden, dass auch eine Implementierung von IObservableVector<IInspectable> bereitgestellt wird.If a C++/WinRT runtime class implements IObservableVector<T>, then we can't assume that an implementation of IObservableVector<IInspectable> is somehow also provided.

Daher muss das vorherige Beispiel folgendermaßen aussehen.Consequently, here's how the previous example will need to look.

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

Die Implementierung sieht dann so aus.And the implementation.

// 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;
};
...

Wenn du auf Objekte in m_bookSkus zugreifen musst, musst du einen QI-Vorgang zurück zu Bookstore::BookSku durchführen.If you need to access objects in m_bookSkus, then you'll need to QI them back to 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;
}

Abgeleitete KlassenDerived classes

Um aus einer Laufzeitklasse abzuleiten, muss die Basisklasse zusammensetzbar sein.In order to derive from a runtime class, the base class must be composable. In C# sind keine besonderen Schritte erforderlich, um Klassen zusammensetzbar zu machen, in C++/WinRT schon.C# doesn't require that you take any special steps to make your classes composable, but C++/WinRT does. Du verwendest das unsealed-Schlüsselwort, um anzugeben, dass die Klasse als Basisklasse verwendet werden kann.You use the unsealed keyword to indicate that you want your class to be usable as a base class.

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

In der Headerdatei deines Implementierungstyps musst du die Basisklassen-Headerdatei einschließen, bevor du den automatisch generierten Header für die abgeleitete Klasse einschließt.In the header file for your implementation type, you must include the base class header file before you include the autogenerated header for the derived class. Andernfalls erhältst du Fehler wie „Ungültige Verwendung dieses Typs als Ausdruck“.Otherwise you'll get errors such as "Illegal use of this type as an expression".

// 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>
    {
        ...
    }
}

Wichtige APIsImportant APIs