Megjegyzés
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhat bejelentkezni vagy módosítani a címtárat.
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhatja módosítani a címtárat.
Tipp
Ha korábban már elolvasta ezt a témakört, és most egy adott feladathoz tér vissza hozzá, akkor közvetlenül a témakör Tartalom keresése az elvégzendő feladat alapján szakaszára ugorhat.
Ez a témakör átfogóan katalogizálja a C#- projekt forráskódjának C++/WinRT-beli megfelelőjéhez való portolásának technikai részleteit.
Az Univerzális Windows-platform (UWP) alkalmazásminták egyikének portolásával kapcsolatos esettanulmányért tekintse meg a vágólap mintájának C++/WinRT-ből C#-ból való portolásával foglalkozó társtémakört. Portolási gyakorlatra és tapasztalatra tehet szert, ha követi ezt az útmutatót, és közben önállóan is portolja a mintát.
A felkészülés és a várható teendők
Az esettanulmány, A Vágólap minta portolása C#-ból C++/WinRT-re, példákon keresztül mutatja be, milyen szoftvertervezési döntéseket kell meghoznia egy projekt C++/WinRT-re történő portolása során. Ezért érdemes felkészülni a portolásra, ha alapos ismereteket szerez a meglévő kód működéséről. Így jó áttekintést kaphat az alkalmazás funkcióiról és a kód szerkezetéről, majd a meghozott döntések mindig a megfelelő irányba viszik előre.
A várható adathordozási változások tekintetében négy kategóriába csoportosíthatja őket.
-
A nyelvi projekció portolása. A Windows-futtatókörnyezet (WinRT) különböző programozási nyelvekre van kivetítve. Mindegyik ilyen nyelvi leképezést úgy tervezték, hogy természetesnek hasson az adott programozási nyelvben. A C# esetében egyes Windows-futtatókörnyezet típusok .NET típusként vannak előrevetítve. Így például a System.Collections.Generic.IReadOnlyList<T> elemet visszafordítja erre: Windows.Foundation.Collections.IVectorView<T>. A C#-ban is néhány Windows-futtatókörnyezet művelet kényelmes C# nyelvi funkciókként van előrevetítve. Ilyen például, hogy a C#-ban az
+=operátor szintaxisával regisztrál egy eseménykezelő meghatalmazottat. Tehát az ilyen nyelvi elemeket vissza fogja vezetni az éppen végrehajtott alapműveletre (ebben a példában az eseményregisztrációra). -
Portnyelv szintaxisa. Ezek közül sok egyszerű mechanikai átalakítás, amely egy szimbólumot cserél egy másikra. Például a pont () kettőspontra (
.::) való módosítása. -
Portnyelvi eljárás. Ezek némelyike lehet egyszerű, ismétlődő módosítás (például
myObject.MyProperty:myObject.MyProperty()). Más esetek mélyebb módosításokat igényelnek (például egy System.Text.StringBuilder használatát magában foglaló eljárás átültetését egy olyanra, amely std::wostringstream használatát foglalja magában). -
A C++/WinRT-hez kapcsolódó portolással kapcsolatos feladatok. A Windows-futtatókörnyezet bizonyos részleteiről a C# implicit módon gondoskodik a színfalak mögött. Ezek a részletek kifejezetten a C++/WinRT-ben érhetők el. Ilyen például, ha egy
.idlfájlt használ a futtatókörnyezeti osztályok definiálásához.
Az alábbi feladatalapú index után a témakör többi szakasza a fenti osztályozás szerint van strukturálva.
Tartalom keresése az éppen elvégzett feladat alapján
| tevékenység | Content |
|---|---|
| Windows-futtatókörnyezet összetevő (WRC) létrehozása | Bizonyos funkciók (vagy bizonyos API-k) csak C++-val érhetők el. Ezt a funkciót beleszámíthatja egy C++/WinRT WRC-be, majd felhasználhatja a WRC-t (például) egy C#-alkalmazásból. Lásd: Windows-futtatókörnyezet-összetevők a C++/WinRT használatával és Ha runtime-osztályt hoz létre egy Windows-futtatókörnyezet-összetevőben. |
| Aszinkron metódus átalakítása | Jó ötlet, ha egy C++/WinRT-futtatókörnyezet osztályában az aszinkron metódus első sora auto lifetime = get_strong(); (lásd: A this mutató biztonságos elérése osztálytag-korutinban).Migrálás innen: Task, lásd: aszinkron művelet.A(z) Task<T> környezetből történő portoláshoz lásd: Aszinkron művelet.Portoláskor innen: async void, lásd: tűz és felejtsd el módszer. |
| Osztály portolása | Először állapítsa meg, hogy az osztálynak futtatókörnyezeti osztálynak kell-e lennie, vagy lehet-e egy szokásos osztály. Ennek eldöntéséhez tekintse meg a Author API-k kezdetét a C++/WinRT használatával. Ezután tekintse meg az alábbi három sort. |
| Futtatókörnyezeti osztály portolása | Olyan osztály, amely a C++ alkalmazáson kívüli funkciókat osztja meg, vagy egy XAML-adatkötésben használt osztály. Tekintse meg, hogy egy futtatókörnyezeti osztályt hoz-e létre egy Windows-futtatókörnyezet összetevőben, vagy ha olyan futtatókörnyezeti osztályt hoz létre, amelyre hivatkozni szeretne az XAML felhasználói felületén. Ezek a hivatkozások részletesebben ismertetik ezt, de egy futtatókörnyezeti osztályt idL-ben kell deklarálni. Ha a projekt már tartalmaz egy IDL-fájlt (például a Project.idl fájlt), azt javasoljuk, hogy az új futtatókörnyezeti osztályt abban a fájlban deklarálja. Az IDL-ben deklaráljon minden olyan metódust és adattagot, amelyet az alkalmazáson kívül fognak használni, vagy amelyeket az XAML-ben fognak használni. Miután frissítette az IDL-fájlt, építse újra, és tekintse meg a létrehozott csonkfájlokat (.hés .cpp) a projekt mappájában Generated Files (Megoldáskezelő a projektcsomópont ki van jelölve, és győződjön meg arról, hogy az Összes fájl megjelenítése kapcsoló be van kapcsolva). Hasonlítsa össze a csonkfájlokat a projektben már szereplő fájlokkal, adjon hozzá fájlokat, vagy szükség szerint adjon hozzá/frissítse a függvény-aláírásokat. A Stub-fájl szintaxisa mindig helyes, ezért azt javasoljuk, hogy a buildelési hibák minimalizálása érdekében használja. Ha a projektben lévő csonkok megegyeznek a csonkfájlokban találhatóakkal, a C#-kód áthordásával implementálhatja őket. |
| Szokásos osztály portja | Lásd: Ha nem ír futtatásidejű osztályt. |
| Szerző IDL |
A Microsoft Interface Definition Language 3.0 bemutatása Ha az XAML felhasználói felületén hivatkozni kívánt futtatókörnyezeti osztályt hoz létre Objektumok használata XAML-jelölőnyelvből Futtatókörnyezeti osztályok definiálása az IDL-ben |
| Gyűjtemény áttelepítése |
Gyűjtemények C++/WinRT használatával Adatforrás elérhetővé tétele az XAML-korrektúra számára Asszociatív tároló Vektortag elérése |
| Esemény portja |
Eseménykezelő delegátus osztálytagként Eseménykezelő delegált visszavonása |
| Metódus átültetése | C#-ból: private async void SampleButton_Tapped(object sender, Microsoft.UI.Xaml.Input.TappedRoutedEventArgs e) { ... }A C++/WinRT .h fájlhoz: fire_and_forget SampleButton_Tapped(IInspectable const&, RoutedEventArgs const&);A C++/WinRT .cpp fájlhoz: fire_and_forget OcrFileImage::SampleButton_Tapped(IInspectable const&, RoutedEventArgs const&) {...} |
| Portkarakterláncok |
Sztringkezelés a C++/WinRT-ben ToString Sztringépítés Sztring dobozolása és kicsomagolása |
| Típuskonvertálás (típus-öntés) | C#: o.ToString()C++/WinRT: to_hstring(static_cast<int>(o))Lásd még : ToString. C#: (Value)oC++/WinRT: unbox_value<Value>(o)Dob, ha a kicsomagolás sikertelen. Lásd még: Boxing and unboxing. C#: o as Value? ?? fallbackC++/WinRT: unbox_value_or<Value>(o, fallback)Visszaesést ad vissza, ha a kicsomagolás sikertelen. Lásd még: Dobozolás és kicsomagolás. C#: (Class)oC++/WinRT: o.as<Class>()Dob, ha az átalakítás sikertelen. C#: o as ClassC++/WinRT: o.try_as<Class>()Null értéket ad vissza, ha az átalakítás sikertelen. |
A nyelvi kivetítés részét képező módosítások
| Category | C# | C++/WinRT | Lásd még |
|---|---|---|---|
| Nem beírt objektum |
objectvagy System.Object |
Windows::Foundation::IInspectable | Az EnableClipboardContentChangedNotifications metódus portolása |
| Vetületi névterek | using System; |
using namespace Windows::Foundation; |
|
using System.Collections.Generic; |
using namespace Windows::Foundation::Collections; |
||
| Gyűjtemény mérete | collection.Count |
collection.Size() |
A BuildClipboardFormatsOutputString metódus portolása |
| Tipikus gyűjteménytípus | IList<T> és Hozzáadás elem hozzáadásához. | IVector<T> és Append elem hozzáadásához. Ha bárhol std::vector-t használ, akkor egy elem hozzáadásához használja a push_back függvényt. | |
| Írásvédett gyűjteménytípus | IReadOnlyList<T> | IVectorView<T> | A BuildClipboardFormatsOutputString metódus portolása |
| Eseménykezelő delegált osztálytagként | myObject.EventName += Handler; |
token = myObject.EventName({ get_weak(), &Class::Handler }); |
Az EnableClipboardContentChangedNotifications metódus portolása |
| Eseménykezelő delegált visszavonása | myObject.EventName -= Handler; |
myObject.EventName(token); |
Az EnableClipboardContentChangedNotifications metódus portolása |
| Asszociatív tároló | IDictionary<K, V> | IMap<K, V> | |
| Vektortag elérése | x = v[i];v[i] = x; |
x = v.GetAt(i);v.SetAt(i, x); |
Eseménykezelő regisztrálása/visszavonása
A C++/WinRT-ben számos szintaktikai lehetőség közül választhat egy eseménykezelő delegált regisztrálására/visszavonására, a C++/WinRT-meghatalmazottak használatával az események kezelése című cikkben leírtak szerint. Lásd még az EnableClipboardContentChangedNotifications metódus portolását.
Előfordulhat például, hogy amikor egy esemény címzettje (egy eseményt kezelő objektum) megsemmisül, vissza kell vonnia egy eseménykezelőt, hogy az eseményforrás (az eseményt növelő objektum) ne hívjon fel megsemmisült objektumot. Lásd: A regisztrált delegált visszavonása. Ilyen esetekben hozzon létre egy event_token tagváltozót az eseménykezelők számára. Példaként lásd: Az EnableClipboardContentChangedNotifications metódus portolása.
Az eseménykezelőt az XAML-jelölőnyelvben is regisztrálhatja.
<Button x:Name="OpenButton" Click="OpenButton_Click" />
A C#-ban a OpenButton_Click metódus privát lehet, és az XAML továbbra is csatlakoztathatja az OpenButton által létrehozott ButtonBase.Click eseményhez.
A C++/WinRT-ben a OpenButton_Click metódusnak nyilvánosnak kell lennie a megvalósítási típusban, ha XAML-korrektúrában szeretné regisztrálni. Ha csak imperatív kódban regisztrál egy eseménykezelőt, akkor az eseménykezelőnek nem kell nyilvánosnak lennie.
namespace winrt::MyProject::implementation
{
struct MyPage : MyPageT<MyPage>
{
void OpenButton_Click(
winrt::Windows::Foundation::IInspectable const& sender,
winrt::Microsoft::UI::Xaml::RoutedEventArgs const& args);
}
};
Alternatív megoldásként a regisztráló XAML-oldalt az implementációtípus barátjává, az OpenButton_Click tagot pedig priváttá teheti.
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);
}
};
Az egyik utolsó forgatókönyv az, amikor a portolt C# projekt a korrektúra alapján köti az eseménykezelőhöz (a forgatókönyv további hátterét lásd: Functions in x:Bind).
<Button x:Name="OpenButton" Click="{x:Bind OpenButton_Click}" />
Egyszerűen módosíthatja azt a jelölést az egyszerűbb Click="OpenButton_Click" formára. Vagy, ha úgy szeretné, megtarthatja változatlanul ezt a jelölést. Ennek támogatásához mindössze annyit kell tennie, hogy deklarálja az eseménykezelőt az IDL-ben.
void OpenButton_Click(Object sender, Microsoft.UI.Xaml.RoutedEventArgs e);
Note
Deklarálja a függvényt void még akkor is, ha implementáljaFire and forget módszerrel.
A nyelvi szintaxist érintő módosítások
| Category | C# | C++/WinRT | Lásd még |
|---|---|---|---|
| Hozzáférési módosítók | public \<member\> |
public:\<member\> |
A Button_Click metódus portolása |
| Adattag elérése | this.variable |
this->variable |
|
| Aszinkron művelet | async Task ... |
IAsyncAction ... |
IAsyncAction interfész, Párhuzamosság és aszinkron műveletek a C++/WinRT-ben |
| Aszinkron művelet | async Task<T> ... |
IAsyncOperation<T> ... |
IAsyncOperation interfész, Párhuzamosság és aszinkron műveletek C++/WinRT használatával |
| Fire-and-forget metódus (aszinkront jelent) | async void ... |
winrt::fire_and_forget ... |
A CopyButton_Click metódus portolása, a Fire és a Forget |
| Enumerált állandó elérése | E.Value |
E::Value |
A DisplayChangedFormats metódus portolása |
| Kooperatív várakozás | await ... |
co_await ... |
A CopyButton_Click metódus portolása |
| Leképezett típusok gyűjteménye privát mezőként | private List<MyRuntimeClass> myRuntimeClasses = new List<MyRuntimeClass>(); |
std::vector<MyNamespace::MyRuntimeClass>m_myRuntimeClasses; |
|
| GUID-konstrukció | 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} }; |
|
| Névtér-elválasztó | A.B.T |
A::B::T |
|
| Null | null |
nullptr |
Az UpdateStatus metódus portolása |
| Típusobjektum beszerzése | typeof(MyType) |
winrt::xaml_typename<MyType>() |
A Forgatókönyvek tulajdonságának portolása |
| Metódus paraméterdeklarációja | MyType |
MyType const& |
Paraméterátadás |
| Paraméterdeklaráció aszinkron metódushoz | MyType |
MyType |
Paraméterátadás |
| Statikus metódus meghívása | T.Method() |
T::Method() |
|
| Húrok |
stringvagy System.String |
winrt::hstring | Sztringkezelés a C++/WinRT-ben |
| Sztring-konstans | "a string literal" |
L"a string literal" |
A konstruktor, a Current és a FEATURE_NAME átültetése |
| Kikövetkeztetett (vagy dedukált) típus | var |
auto |
A BuildClipboardFormatsOutputString metódus portolása |
| Irányelv használata | using A.B.C; |
using namespace A::B::C; |
A konstruktor, a Current és a FEATURE_NAME átültetése |
| Verbatim/nyers sztringkonstans | @"verbatim string literal" |
LR"(raw string literal)" |
A DisplayToast metódus portolása |
Note
Ha egy fejlécfájl nem tartalmaz using namespace egy adott névtérre vonatkozó direktívát, akkor az adott névtér összes típusnevét teljes mértékben minősíteni kell, vagy legalább megfelelőnek kell lennie ahhoz, hogy a fordító megtalálja őket. Például lásd: DisplayToast metódus portolása.
Osztályok és tagok portolása
Minden C#-típus esetében el kell döntenie, hogy egy Windows-futtatókörnyezet típusba vagy egy normál C++ osztályba/struct/enumerálásba szeretné-e portolni. További információkért és részletes példákért, amelyek bemutatja, hogyan hozhatja meg ezeket a döntéseket, tekintse meg a vágólap mintájának C++/WinRT-fájlba való portolását a C#-ból.
A C#-tulajdonság általában egy kiegészítő függvény, egy mutációs függvény és egy háttéradat-tag lesz. További információ és példa: IsClipboardContentChangedEnabled tulajdonság portolása.
Nem statikus mezők esetén tegye őket a megvalósítási típus adattagjaivá.
A C# statikus mező C++/WinRT statikus kiegészítő és/vagy mutációs függvény lesz. További információkért és egy példáért lásd: A konstruktor, a Current és a FEATURE_NAME átültetése.
A tagfüggvények esetében ismét el kell döntenie minden egyes függvénynél, hogy belekerüljön-e az IDL-be, vagy az implementációs típus nyilvános vagy privát tagfüggvénye legyen. További információkért és a döntési módra vonatkozó példákért tekintse meg a MainPage típus IDL-ját.
A XAML-jelölőnyelv és az erőforrásfájlok átvitele
Abban az esetben, ha a vágólap mintáját C++/WinRT-fájlba portoljuk C#-ból, ugyanazt az XAML-korrektúrát (beleértve az erőforrásokat) és az eszközfájlokat is használhattuk a C# és a C++/WinRT projektben. Bizonyos esetekben a korrektúra szerkesztése szükséges lesz ennek eléréséhez. Lásd: A MainPage portolásának befejezéséhez szükséges XAML és stílusok másolása.
A nyelven belüli eljárásokat érintő változások
| Category | C# | C++/WinRT | Lásd még |
|---|---|---|---|
| Élettartam-kezelés aszinkron metódusban | N/A |
auto lifetime{ get_strong() }; vagyauto lifetime = get_strong(); |
A CopyButton_Click metódus portolása |
| Kivezetés | using (var t = v) |
auto t{ v };t.Close(); // or let wrapper destructor do the work |
A CopyImage metódus portolása |
| Objektum létrehozása | new MyType(args) |
MyType{ args } vagyMyType(args) |
A Forgatókönyvek tulajdonság portolása |
| Nem inicializált referencia létrehozása | MyType myObject; |
MyType myObject{ nullptr }; vagyMyType myObject = nullptr; |
A konstruktor, a Current és a FEATURE_NAME átültetése |
| Objektum létrehozása változóban argumentumokkal | var myObject = new MyType(args); |
auto myObject{ MyType{ args } }; vagy auto myObject{ MyType(args) }; vagy auto myObject = MyType{ args }; vagy auto myObject = MyType(args); vagy MyType myObject{ args }; vagy MyType myObject(args); |
A Footer_Click metódus portolása |
| Objektum létrehozása változóban argumentumok nélkül | var myObject = new T(); |
MyType myObject; |
A BuildClipboardFormatsOutputString metódus portolása |
| Objektum inicializálásának rövidítése | var p = new FileOpenPicker{ViewMode = PickerViewMode.List}; |
FileOpenPicker p;p.ViewMode(PickerViewMode::List); |
|
| Tömeges vektorművelet | var p = new FileOpenPicker{FileTypeFilter = { ".png", ".jpg", ".gif" }}; |
FileOpenPicker p;p.FileTypeFilter().ReplaceAll({ L".png", L".jpg", L".gif" }); |
A CopyButton_Click metódus portolása |
| Végigiterálni a gyűjteményen | foreach (var v in c) |
for (auto&& v : c) |
A BuildClipboardFormatsOutputString metódus portolása |
| Kivétel elfogása | catch (Exception ex) |
catch (winrt::hresult_error const& ex) |
A PasteButton_Click metódus portolása |
| Kivétel részletei | ex.Message |
ex.message() |
A PasteButton_Click metódus portolása |
| Tulajdonságérték lekérése | myObject.MyProperty |
myObject.MyProperty() |
A NotifyUser metódus portolása |
| Tulajdonságérték beállítása | myObject.MyProperty = value; |
myObject.MyProperty(value); |
|
| Tulajdonságérték növelése | myObject.MyProperty += v; |
myObject.MyProperty(thing.Property() + v);Karakterláncok esetén használjon karakterlánc-összefűzőt |
|
| ToString() | myObject.ToString() |
winrt::to_hstring(myObject) |
ToString() |
| Nyelvi karakterlánc – Windows-futtatókörnyezet-karakterlánc | N/A | winrt::hstring{ s } |
|
| Sztringépítés | StringBuilder builder;builder.Append(...); |
std::wostringstream builder;builder << ...; |
Sztringépítés |
| Sztring interpolációja | $"{i++}) {s.Title}" |
winrt::to_hstring és/vagy winrt::hstring::operator+ | Az OnNavigatedTo metódus portolása |
| Üres sztring összehasonlításhoz | System.String.Empty | winrt::hstring::empty | Az UpdateStatus metódus portolása |
| Üres sztring létrehozása | var myEmptyString = String.Empty; |
winrt::hstring myEmptyString{ L"" }; |
|
| Szótári műveletek | 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) |
|
| Típuskonvertálás (hiba esetén) | (MyType)v |
v.as<MyType>() |
A Footer_Click metódus portolása |
| Típuskonvertálás (hiba esetén null érték) | v as MyType |
v.try_as<MyType>() |
A PasteButton_Click metódus portolása |
| Az x:Name tulajdonsággal rendelkező XAML-elemek tulajdonságok | MyNamedElement |
MyNamedElement() |
A konstruktor, a Current és a FEATURE_NAME átültetése |
| Váltás a felhasználói felületi szálra | CoreDispatcher.RunAsync | DispatcherQueue.TryEnqueue vagy winrt::resume_foreground | A NotifyUser metódus portolása és a HistoryAndRoaming metódus portolása |
| Felhasználói felületi elem felépítése imperatív kódban XAML-lapon | Lásd : felhasználói felületi elem felépítése | Lásd : felhasználói felületi elem felépítése |
Az alábbi szakaszok részletesebben ismertetik a táblázat egyes elemeit.
Felhasználói felületi elem felépítése
Ezek a példakódok egy felhasználói felületi elem felépítését mutatják be egy XAML-oldal imperatív kódjában.
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()
A C#-típusok biztosítják az Object.ToString metódust .
int i = 2;
var s = i.ToString(); // s is a System.String with value "2".
A C++/WinRT közvetlenül nem biztosítja ezt a létesítményt, de alternatív megoldásokhoz fordulhat.
int i{ 2 };
auto s{ std::to_wstring(i) }; // s is a std::wstring with value L"2".
A C++/WinRT a winrt::to_hstring is támogatja korlátozott számú típus esetén. Túlterheléseket kell hozzáadnia minden további sztringbefűzni kívánt típushoz.
| Nyelv | Stringify int | Felsorolás karakterlánccá alakítása |
|---|---|---|
| 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); |
Enum sztringelése esetén meg kell adnia a winrt::to_hstring implementációját.
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));
}
}
}
Ezeket a karakterlánccá alakított értékeket az adatkötés gyakran implicit módon használja fel.
<TextBlock>
You have <Run Text="{Binding FlowerCount}"/> flowers.
</TextBlock>
<TextBlock>
Most recent status is <Run Text="{x:Bind LatestOperation.Status}"/>.
</TextBlock>
Ezek a kötések végrehajtják a kötött tulajdonság winrt::to_hstring értékét. A második példa (a StatusEnum) esetében a winrt::to_hstring saját túlterhelését kell megadnia, ellenkező esetben fordítóhiba jelenik meg.
Lásd még a Footer_Click metódus portolását.
Sztringépítés
Karakterláncok összeállításához a C# beépített StringBuilder típussal rendelkezik.
| Category | C# | C++/WinRT |
|---|---|---|
| Sztringépítés | StringBuilder builder;builder.Append(...); |
std::wostringstream builder;builder << ...; |
| Windows-futtatókörnyezet-karakterlánc hozzáfűzése a null karakterek megőrzésével | builder.Append(s); |
builder << std::wstring_view{ s }; |
| Új vonal hozzáadása | builder.Append(Environment.NewLine); |
builder << std::endl; |
| Az eredmény elérése | s = builder.ToString(); |
ws = builder.str(); |
Lásd még a BuildClipboardFormatsOutputString metódus portolását és a DisplayChangedFormats metódus portolását.
Kód futtatása a fő felhasználói felületi szálon
Ez a példa a vonalkódolvasó mintájából származik.
Ha egy C#-projekt fő felhasználói felületi szálán szeretne dolgozni, általában a DispatcherQueue.TryEnqueue metódust (vagy a régebbi CoreDispatcher.RunAsyncet használja az UWP-ben). Így néz ki a minta a C#-ban.
private async void Watcher_Added(DeviceWatcher sender, DeviceInformation args)
{
DispatcherQueue.TryEnqueue(() =>
{
// Do work on the main UI thread here.
});
}
Sokkal egyszerűbb ezt a C++/WinRT-ben kifejezni. Figyelje meg, hogy a paramétereket érték szerint fogadjuk el, feltételezve, hogy az első felfüggesztési pont (ebben az esetben) co_awaitután szeretnénk elérni őket. További információ: Paraméterátadás.
winrt::fire_and_forget Watcher_Added(DeviceWatcher sender, winrt::DeviceInformation args)
{
co_await DispatcherQueue();
// Do work on the main UI thread here.
}
Ha nem az alapértelmezett prioritáson kell elvégeznie a munkát, akkor tekintse meg a winrt::resume_foreground függvényt, amelynek túlterhelése prioritást vesz igénybe. A winrt::resume_foreground hívására való várakozást bemutató kódpéldákat lásd itt: A szálaffinitást szem előtt tartó programozás.
A C++/WinRT-hez kapcsolódó portolással kapcsolatos feladatok
Definiálja a futtatókörnyezeti osztályait IDL-ben
Lásd a MainPage típus IDL-jét, és vond össze a .idl fájlokat.
Adja meg a szükséges C++/WinRT-Windows névtérfejlécfájlokat
A C++/WinRT-ben minden alkalommal, amikor Windows névterekből szeretne típust használni, a megfelelő C++/WinRT Windows névtérfejlécfájlt kell tartalmaznia. Példa: A NotifyUser metódus portolása.
Dobozolás és kicsomagolás
A C# automatikusan a skaláris elemeket objektumokká alakítja. A C++/WinRT megköveteli a winrt::box_value függvény explicit meghívását. Mindkét nyelvben expliciten kell kicsomagolni. Lásd: Boxolás és kicsomagolás a C++/WinRT használatával.
Az alábbi táblázatokban ezeket a definíciókat fogjuk használni.
| C# | C++/WinRT |
|---|---|
int i; |
int i; |
string s; |
winrt::hstring s; |
object o; |
IInspectable o; |
| Operation | C# | C++/WinRT |
|---|---|---|
| Ökölvívás | o = 1;o = "string"; |
o = box_value(1);o = box_value(L"string"); |
| Kicsomagolás | i = (int)o;s = (string)o; |
i = unbox_value<int>(o);s = unbox_value<winrt::hstring>(o); |
A C++/CX és a C# kivételt vált ki, ha nullértékű mutatót próbál értéktípussá kibontani. A C++/WinRT ezt programozási hibának tekinti, és összeomlik. A C++/WinRT-ben használja a winrt::unbox_value_or függvényt, ha azt az esetet szeretné kezelni, amelyben az objektum nem az ön által vélt típus.
| Scenario | C# | C++/WinRT |
|---|---|---|
| Ismert egész szám kicsomagolása | i = (int)o; |
i = unbox_value<int>(o); |
| Ha o null | System.NullReferenceException |
Lezuhan |
| Ha o nem dobozos int | System.InvalidCastException |
Lezuhan |
| Az int kicsomagolása, null érték esetén tartalékérték használata; minden más esetben összeomlás | i = o != null ? (int)o : fallback; |
i = o ? unbox_value<int>(o) : fallback; |
| Ha lehetséges, csomagolja ki az intet; minden más esetben használjon tartalék megoldást | i = as int? ?? fallback; |
i = unbox_value_or<int>(o, fallback); |
Példa: Az OnNavigatedTo metódus portolása és a Footer_Click metódus portolása.
Sztring dobozolása és kicsomagolása
A sztringek valamilyen módon értéktípust, más módon pedig referenciatípust jelentek. A C# és a C++/WinRT eltérően kezeli a sztringeket.
Az ABI típusú HSTRING egy referenciaszámlált karakterláncra mutató mutató. De nem az IInspectable-ból származik, tehát technikailag nem objektum. Ezenkívül a null HSTRING az üres sztringet jelöli. Az IInspectable-ból nem származó dolgok dobozolása úgy történik, hogy egy IReference<T-be> burkolja őket, és a Windows-futtatókörnyezet egy standard implementációt biztosít a PropertyValue objektum formájában (az egyéni típusok tulajdonságtípusként vannak jelentve::OtherType).
A C# hivatkozástípusként Windows-futtatókörnyezet sztringet jelöl, míg a C++/WinRT értéktípusként egy sztringet. Ez azt jelenti, hogy egy becsomagolt null sztring attól függően különbözőképpen ábrázolható, hogy hogyan jutottunk el idáig.
| Behavior | C# | C++/WinRT |
|---|---|---|
| Nyilatkozatok | object o;string s; |
IInspectable o;hstring s; |
| Sztringtípus kategóriája | Hivatkozás típusa | Érték típusa |
| null HSTRING formában jelenik meg | "" |
hstring{} |
Null és "" azonos? |
No | Yes |
| Null érték érvényessége | s = null;s.Length NullReferenceException értéket ad meg |
s = hstring{};s.size() == 0 (érvényes) |
| Ha null sztringet rendel az objektumhoz | o = (string)null;o == null |
o = box_value(hstring{});o != nullptr |
Ha objektumhoz rendel "" |
o = "";o != null |
o = box_value(hstring{L""});o != nullptr |
Alapszintű ökölvívás és kicsomagolás.
| Operation | C# | C++/WinRT |
|---|---|---|
| Karakterlánc becsomagolása | o = s;Az üres sztring nem null értékű objektummá válik. |
o = box_value(s);Az üres sztring nem null értékű objektummá válik. |
| Ismert karakterlánc kibontása | s = (string)o;A null objektum null sztring lesz. InvalidCastException, ha az érték nem karakterlánc. |
s = unbox_value<hstring>(o);Null objektum összeomlik. Összeomlik, ha nem karakterlánc. |
| Opcionális karakterlánc kibontása | s = o as string;A nullobjektum vagy a nem karakterlánc null karakterlánccá válik. OR s = o as string ?? fallback;A null vagy nem karakterlánc típusú érték helyett az alapértelmezett érték lesz használva. Üres sztring megőrzve. |
s = unbox_value_or<hstring>(o, fallback);A null vagy nem karakterlánc típusú érték helyett az alapértelmezett érték lesz használva. Üres sztring megőrzve. |
Osztály elérhetővé tétele a {Binding} korrektúrabővítmény számára
Ha a {Binding} korrektúrakiterjesztést az adattípushoz való adatkötéshez szeretné használni, tekintse meg a {Binding} használatával deklarált Kötés objektumot.
Objektumok használata XAML-jelölőnyelvből
Egy C#-projektben hozzáférhet a XAML-jelölőnyelv privát tagjaihoz és elnevezett elemeihez. A C++/WinRT rendszerben azonban az XAML {x:Bind} jelölőbővítménnyel felhasznált összes entitást nyilvánosan közzé kell tenni az IDL-ben.
Emellett a logikai értékhez való kötés C#-ban a true vagy false értéket jeleníti meg, míg C++/WinRT-ben a Windows.Foundation.IReference`1<Boolean> látható.
További információkért és kódpéldákért lásd Objektumok felhasználása jelölőnyelvből.
Adatforrás elérhetővé tétele a XAML-jelölőnyelv számára
A C++/WinRT 2.0.190530.8-s vagy újabb verziójában a winrt::single_threaded_observable_vector egy megfigyelhető vektort hoz létre, amely támogatja az IObservableVector<T> és az IObservableVector<IInspectable protokollt> is. Példaként lásd: a Forgatókönyvek tulajdonság portolása.
A MIDL-fájlt (.idl) így is megírhatja (lásd még: Futtatásidejű osztályok szétválasztása MIDL-fájlokba (.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; };
}
}
És valósítsuk meg így.
// 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;
};
...
További információ: XAML-elemek vezérlői; C++/WinRT-gyűjteményhez kötés, gyűjtemények C++/WinRT használatával.
Adatforrás elérhetővé tétele az XAML-korrektúra számára (a C++/WinRT 2.0.190530.8 előtt)
Az XAML-adatkötés megköveteli, hogy egy elemforrás megvalósítsa az IIterable<IInspectablet>, valamint az alábbi illesztőkombinációk egyikét.
- IObservableVector<IInspectable>
- IBindableVector és INotifyCollectionChanged
- IBindableVector és IBindableObservableVector
- IBindableVector önmagában (nem válaszol a változásokra)
- IVector<IInspectable>
- IBindableIterable (iterálja és menti az elemeket egy privát gyűjteménybe)
Egy általános felület, például az IVector<T> nem észlelhető futásidőben. Minden IVector<T> más interfészazonosítóval (IID) rendelkezik, amely a T függvénye. Bármely fejlesztő tetszőlegesen ki tudja bontani a T halmazt, így az XAML kötési kód egyértelműen soha nem tudja a teljes lekérdezési készletet. Ez a korlátozás nem jelent problémát a C# esetében, mert minden, az IEnumerable<T-t> implementáló CLR-objektum automatikusan implementálja az IEnumerable-t. Az ABI szintjén ez azt jelenti, hogy az IObservableVector<T-t> implementáló összes objektum automatikusan implementálja az IObservableVector<IInspectablet>.
A C++/WinRT nem biztosítja ezt a garanciát. Ha egy C++/WinRT futtatókörnyezeti osztály implementálja az IObservableVector<T-t>, akkor nem feltételezhetjük, hogy az IObservableVector<IInspectable> implementációja is meg van adva.
Következésképpen az előző példának így kell kinéznie.
...
runtimeclass BookstoreViewModel
{
// This is really an observable vector of BookSku.
Windows.Foundation.Collections.IObservableVector<Object> BookSkus{ get; };
}
És a megvalósítás.
// 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;
};
...
Ha hozzá kell férnie az m_bookSkus-ban lévő objektumokhoz, akkor vissza kell QI-znia őket erre: 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;
}
Származtatott osztályok
A futtatókörnyezeti osztályból való levezetéshez az alaposztálynak összeállíthatónak kell lennie. A C# nem követeli meg, hogy bármilyen speciális lépést tegyen az osztályai komponálhatóvá tételéhez, a C++/WinRT azonban igen. Az unsealed kulcsszó arra szolgál, hogy jelezze, hogy az osztály alaposztályként használható.
unsealed runtimeclass BasePage : Microsoft.UI.Xaml.Controls.Page
{
...
}
runtimeclass DerivedPage : BasePage
{
...
}
A megvalósítási típus fejlécfájljában az alaposztály fejlécfájlját kell tartalmaznia, mielőtt belefoglalja a származtatott osztály automatikusan létrehozott fejlécét. Ellenkező esetben olyan hibaüzenetek jelennek meg, mint például "Az ilyen típusú kifejezések tiltott használata".
// 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>
{
...
}
}
Fontos API-k
Kapcsolódó témakörök
- C#-oktatóanyagok
- C++/WinRT
- Részletes adatkötés
Windows developer