Behandeln von Ereignissen mithilfe von Delegaten in C++/WinRTHandle events by using delegates in C++/WinRT

In diesem Thema erfährst du, wie du Delegaten, die Ereignisse behandeln, mit C++/WinRT registrierst und widerrufst.This topic shows how to register and revoke event-handling delegates using C++/WinRT. Du kannst ein Ereignis mit jedem funktionsähnlichen C++-Standardobjekt behandeln.You can handle an event using any standard C++ function-like object.

Hinweis

Informationen zum Installieren und Verwenden der C++/WinRT Visual Studio-Erweiterung (VSIX) und des NuGet-Pakets (die zusammen die Projektvorlage und Buildunterstützung bereitstellen) findest du unter Visual Studio-Unterstützung für C++/WinRT.For info about installing and using the C++/WinRT Visual Studio Extension (VSIX) and the NuGet package (which together provide project template and build support), see Visual Studio support for C++/WinRT.

Hinzufügen eines Ereignishandlers mithilfe von Visual Studio 2019Using Visual Studio 2019 to add an event handler

Mit der XAML-Designer-Benutzeroberfläche in Visual Studio 2019 lassen sich Ereignishandler einfach zu Projekten hinzufügen.A convenient way of adding an event handler to your project is by using the XAML Designer user interface (UI) in Visual Studio 2019. Öffnen Sie im XAML-Designer die XAML-Seite, und wählen Sie das Steuerelement aus, dessen Ereignis behandelt werden soll.With your XAML page open in the XAML Designer, select the control whose event you want to handle. Klicken Sie auf der Eigenschaftenseite für dieses Steuerelement auf das Blitzsymbol, um alle Ereignisse aufzulisten, die mit dem Steuerelement verknüpft sind.Over in the property page for that control, click on the lightning-bolt icon to list all of the events that are sourced by that control. Doppelklicken Sie dann auf das Ereignis, das behandelt werden soll, z. B.auf OnClicked.Then, double-click on the event that you want to handle; for example, OnClicked.

Der XAML-Designer fügt den Quelldateien den entsprechenden Ereignishandler-Funktionsprototyp (und eine Stubimplementierung) hinzu, den Sie durch eine eigene Implementierung ersetzen können.The XAML Designer adds the appropriate event handler function prototype (and a stub implementation) to your source files, ready for you to replace with your own implementation.

Hinweis

Die Ereignishandler müssen in der Regel nicht in der Midl-Datei (.idl) beschrieben werden.Typically, your event handlers don't need to be described in your Midl file (.idl). Deshalb fügt der XAML-Designer keine Ereignishandler-Funktionsprototypen zur Midl-Datei hinzu.So, the XAML Designer doesn't add event handler function prototypes to your Midl file. Er fügt sie nur den .h- und .cpp-Dateien hinzu.It only adds them your .h and .cpp files.

Registrieren eines Delegaten zum Behandeln eines EreignissesRegister a delegate to handle an event

Ein einfaches Beispiel ist die Behandlung des Klickereignisses einer Schaltfläche.A simple example is handling a button's click event. In der Regel wird XAML-Markup verwendet, um eine Memberfunktion für die Behandlung des Ereignisses zu registrieren:It's typical to use XAML markup to register a member function to handle the event, like this.

// MainPage.xaml
<Button x:Name="myButton" Click="ClickHandler">Click Me</Button>
// MainPage.h
void ClickHandler(
    winrt::Windows::Foundation::IInspectable const& sender,
    winrt::Windows::UI::Xaml::RoutedEventArgs const& args);

// MainPage.cpp
void MainPage::ClickHandler(
    IInspectable const& /* sender */,
    RoutedEventArgs const& /* args */)
{
    myButton().Content(box_value(L"Clicked"));
}

Der obige Code stammt aus dem Blank App (C++/WinRT) -Projekt in Visual Studio.The code above is taken from the Blank App (C++/WinRT) project in Visual Studio. Der Code myButton() ruft eine generierte Accessorfunktion [XQuery] auf, die das Button-Element zurückgibt, das wir myButton genannt haben.The code myButton() calls a generated accessor function, which returns the Button that we named myButton. Wenn Sie das x:Name-Objekt dieses Button-Elements ändern, ändert sich auch der Name der generierten Accessorfunktion.If you change the x:Name of that Button element, then the name of the generated accessor function changes, too.

Hinweis

In diesem Fall ist die Ereignisquelle (das Objekt, das das Ereignis auslöst) das Button-Element namens myButton.In this case, the event source (the object that raises the event) is the Button named myButton. Und der Ereignisempfänger (das Objekt, das das Ereignis behandelt) ist eine Instanz von MainPage.And the event recipient (the object handling the event) is an instance of MainPage. Weitere Informationen zur Verwaltung der Lebensdauer von Ereignisquellen und Ereignisempfängern finden Sie weiter unten in diesem Thema.There's more info later in this topic about managing the lifetime of event sources and event recipients.

Alternativ kannst du auch imperativ eine Memberfunktion für die Behandlung eines Ereignisses registrieren, anstatt eine Deklaration im Markup zu verwenden.Instead of doing it declaratively in markup, you can imperatively register a member function to handle an event. Es ist vielleicht nicht auf den ersten Blick ersichtlich, aber das Argument für den Aufruf ButtonBase::Click im folgenden Code ist eine Instanz des Delegaten RoutedEventHandler.It may not be obvious from the code example below, but the argument to the ButtonBase::Click call is an instance of the RoutedEventHandler delegate. In diesem Fall verwenden wir die Konstruktorüberladung RoutedEventHandler, die ein Objekt und eine Pointer-to-Member-Funktion akzeptiert.In this case, we're using the RoutedEventHandler constructor overload that takes an object and a pointer-to-member-function.

// MainPage.cpp
MainPage::MainPage()
{
    InitializeComponent();

    myButton().Click({ this, &MainPage::ClickHandler });
}

Wichtig

Beim Registrieren des Delegaten wird im obigen Codebeispiel ein unformatierter Zeiger vom Typ this übergeben, der auf das aktuelle Objekt verweist.When registering the delegate, the code example above passes a raw this pointer (pointing to the current object). In Wenn Sie eine Memberfunktion als Stellvertretung verwenden wird beschrieben, wie Sie einen starken oder schwachen Verweis auf das aktuelle Objekt erstellen.To learn how to establish a strong or a weak reference to the current object, see If you use a member function as a delegate.

Hier ist ein Beispiel, das eine statische Memberfunktion verwendet; beachten Sie die einfachere Syntax.Here's an example that uses a static member function; note the simpler syntax.

// MainPage.h
static void ClickHandler(
    winrt::Windows::Foundation::IInspectable const& sender,
    winrt::Windows::UI::Xaml::RoutedEventArgs const& args);

// MainPage.cpp
MainPage::MainPage()
{
    InitializeComponent();

    myButton().Click( MainPage::ClickHandler );
}
void MainPage::ClickHandler(
    IInspectable const& /* sender */,
    RoutedEventArgs const& /* args */) { ... }

Ein Handler vom Typ RoutedEventHandler kann auch noch auf andere Weise erstellt werden.There are other ways to construct a RoutedEventHandler. Der folgende Syntaxblock stammt aus dem Dokumentationsthema für RoutedEventHandler. (Wähle rechts oben auf dieser Webseite im Dropdownmenü Sprache die Option C++/WinRT aus.)Below is the syntax block taken from the documentation topic for RoutedEventHandler (choose C++/WinRT from the Language drop-down in the upper-right corner of the webpage). Beachte die verschiedenen Konstruktoren: Einer akzeptiert eine Lambda-Funktion, ein anderer eine freie Funktion und ein weiterer (der oben verwendete) ein Objekt sowie eine Pointer-to-Member-Funktion.Notice the various constructors: one takes a lambda; another a free function; and another (the one we used above) takes an object and a pointer-to-member-function.

struct RoutedEventHandler : winrt::Windows::Foundation::IUnknown
{
    RoutedEventHandler(std::nullptr_t = nullptr) noexcept;
    template <typename L> RoutedEventHandler(L lambda);
    template <typename F> RoutedEventHandler(F* function);
    template <typename O, typename M> RoutedEventHandler(O* object, M method);
    void operator()(winrt::Windows::Foundation::IInspectable const& sender,
        winrt::Windows::UI::Xaml::RoutedEventArgs const& e) const;
};

Die Syntax des Funktionsaufrufoperators ist ebenfalls hilfreich.The syntax of the function call operator is also helpful to see. Sie gibt Aufschluss über die benötigten Delegatparameter.It tells you what your delegate's parameters need to be. Wie du siehst, entspricht in diesem Fall die Syntax des Funktionsaufrufoperators den Parametern unseres Handlers vom Typ MainPage::ClickHandler.As you can see, in this case the function call operator syntax matches the parameters of our MainPage::ClickHandler.

Hinweis

Navigiere zum Ermitteln der Details eines Ereignisdelegaten sowie der zugehörigen Parameter zunächst zum Dokumentationsthema für das Ereignis.For any given event, to figure out the details of its delegate, and that delegate's parameters, go first to the documentation topic for the event itself. Nehmen wir beispielsweise das Ereignis „UIElement.KeyDown“.Let's take the UIElement.KeyDown event as an example. Rufe dieses Thema auf, und wähle in der Dropdownliste Sprache die Option C++/WinRT aus.Visit that topic, and choose C++/WinRT from the Language drop-down. Der Syntaxblock am Anfang des Themas enthält Folgendes:In the syntax block at the beginning of the topic, you'll see this.

// Register
event_token KeyDown(KeyEventHandler const& handler) const;

Hier kannst du sehen, dass das Ereignis UIElement.KeyDown (das aufgerufene Thema) den Delegattyp KeyEventHandler besitzt, da dieser Typ beim Registrieren eines Delegaten mit diesem Ereignistyp übergeben wird.That info tells us that the UIElement.KeyDown event (the topic we're on) has a delegate type of KeyEventHandler, since that's the type that you pass when you register a delegate with this event type. Klicke in dem Thema auf den Link zu diesem Delegattyp (KeyEventHandler).So, now follow the link on the topic to that KeyEventHandler delegate type. Der dort bereitgestellte Syntaxblock enthält einen Funktionsaufrufoperator.Here, the syntax block contains a function call operator. Und dieser gibt wie bereits erwähnt Aufschluss über die benötigten Delegatparameter.And, as mentioned above, that tells you what your delegate's parameters need to be.

void operator()(
  winrt::Windows::Foundation::IInspectable const& sender,
  winrt::Windows::UI::Xaml::Input::KeyRoutedEventArgs const& e) const;

Wie du siehst, muss der Delegat deklariert werden, um ein Element vom Typ IInspectable als Absender und eine Instanz der Klasse „KeyRoutedEventArgs“ als Argumente zu akzeptieren.As you can see, the delegate needs to be declared to take an IInspectable as the sender, and an instance of the KeyRoutedEventArgs class as the args.

Sehen wir uns ein weiteres Beispiel an: das Ereignis „Popup.Closed“.To take another example, let's look at the Popup.Closed event. Sein Delegattyp ist EventHandler<IInspectable>.Its delegate type is EventHandler<IInspectable>. Dein Delegat akzeptiert also ein Element vom Typ IInspectable als Absender und ein weiteres Element vom Typ IInspectable als Argumente (da es sich dabei um den Typparameter von EventHandler handelt).So, your delegate will take an IInspectable as the sender, and another IInspectable (because that's the EventHandler's type parameter ) as the args.

Wenn dein Ereignishandler nicht viel zu tun hat, kannst du anstelle einer Memberfunktion eine Lambda-Funktion verwenden.If you're not doing much work in your event handler, then you can use a lambda function instead of a member function. Auch hier ist es vielleicht nicht auf den ersten Blick ersichtlich, aber im folgenden Codebeispiel wird ein Delegat vom Typ RoutedEventHandler auf der Grundlage einer Lambda-Funktion erstellt, und auch hier muss wieder die entsprechende Syntax des oben erläuterten Funktionsaufrufoperators verwendet werden.Again, it may not be obvious from the code example below, but a RoutedEventHandler delegate is being constructed from a lambda function which, again, needs to match the syntax of the function call operator that we discussed above.

MainPage::MainPage()
{
    InitializeComponent();

    myButton().Click([this](IInspectable const& /* sender */, RoutedEventArgs const& /* args */)
    {
        myButton().Content(box_value(L"Clicked"));
    });
}

Ein Delegat kann auch etwas expliziter konstruiert werden.You can choose to be a little more explicit when you construct your delegate. Beispielsweise, wenn du ihn weitergeben oder mehrmals verwenden möchtest.For example, if you want to pass it around, or use it more than once.

MainPage::MainPage()
{
    InitializeComponent();

    auto click_handler = [](IInspectable const& sender, RoutedEventArgs const& /* args */)
    {
        sender.as<winrt::Windows::UI::Xaml::Controls::Button>().Content(box_value(L"Clicked"));
    };
    myButton().Click(click_handler);
    AnotherButton().Click(click_handler);
}

Widerrufen eines registrierten DelegatenRevoke a registered delegate

Wenn du einen Delegaten registrierst, wird in der Regel ein Token zurückgegeben.When you register a delegate, typically a token is returned to you. Mit diesem Token kannst du später deinen Delegaten widerrufen. Dadurch wird die Registrierung des Delegaten für das Ereignis aufgehoben, und er wird nicht mehr aufgerufen, wenn das Ereignis erneut ausgelöst wird.You can subsequently use that token to revoke your delegate; meaning that the delegate is unregistered from the event, and won't be called should the event be raised again.

Dies wurde der Einfachheit halber in keinem der obigen Codebeispiele gezeigt.For the sake of simplicity, none of the code examples above showed how to do that. Im nächsten Codebeispiel wird das Token allerdings im privaten Datenmember der Struktur gespeichert und der zugehörige Handler im Destruktor widerrufen.But this next code example stores the token in the struct's private data member, and revokes its handler in the destructor.

struct Example : ExampleT<Example>
{
    Example(winrt::Windows::UI::Xaml::Controls::Button const& button) : m_button(button)
    {
        m_token = m_button.Click([this](IInspectable const&, RoutedEventArgs const&)
        {
            // ...
        });
    }
    ~Example()
    {
        m_button.Click(m_token);
    }

private:
    winrt::Windows::UI::Xaml::Controls::Button m_button;
    winrt::event_token m_token;
};

Anstelle eines starken Verweises wie im obigen Beispiel kannst du einen schwachen Verweis auf die Schaltfläche speichern (siehe Starke und schwache Verweise in C++/WinRT).Instead of a strong reference, as in the example above, you can store a weak reference to the button (see Strong and weak references in C++/WinRT).

Hinweis

Wenn eine Ereignisquelle die Ereignisse synchron auslöst, kannst du den Handler widerrufen und sicher sein, dass keine weiteren Ereignisse empfangen werden.When an event source raises its events synchronously, you can revoke your handler and be confident that you won't receive any more events. Bei asynchronen Ereignissen kann jedoch auch nach dem Widerrufen (insbesondere bei einem Widerruf innerhalb des Destruktors) ein In-Flight-Ereignis das Objekt erreichen, nachdem mit der Zerstörung begonnen wurde.But for asynchronous events, even after revoking (and especially when revoking within the destructor), an in-flight event might reach your object after it has started destructing. Das Problem lässt sich möglicherweise minimieren, indem die Abonnierung vor der Zerstörung aufgehoben wird. Eine stabilere Lösung findest du jedoch unter Sicherer Zugriff auf den this-Zeiger in einer Klassenmember-Coroutine.Finding a place to unsubscribe prior to destruction might mitigate the issue, or for a robust solution see Safely accessing the this pointer with an event-handling delegate.

Alternativ kannst du bei der Registrierung eines Delegaten winrt::auto_revoke (ein Wert vom Typ winrt::auto_revoke_t) angeben, um einen Ereignis-Revoker (vom Typ winrt::event_revoker) anzufordern.Alternatively, when you register a delegate, you can specify winrt::auto_revoke (which is a value of type winrt::auto_revoke_t) to request an event revoker (of type winrt::event_revoker). Der Ereignis-Revoker enthält einen schwachen Verweis auf die Ereignisquelle (das Objekt, das das Ereignis auslöst).The event revoker holds a weak reference to the event source (the object that raises the event) for you. Zum manuellen Widerrufen kannst du die Memberfunktion event_revoker::revoke aufrufen. Der Ereignis-Revoker ruft diese Funktion bei Verlassen des Gültigkeitsbereichs aber automatisch selbst auf.You can manually revoke by calling the event_revoker::revoke member function; but the event revoker calls that function itself automatically when it goes out of scope. Die Funktion revoke überprüft, ob die Ereignisquelle noch vorhanden ist, und widerruft in diesem Fall deinen Delegaten.The revoke function checks whether the event source still exists and, if so, revokes your delegate. In diesem Beispiel muss die Ereignisquelle nicht gespeichert werden, und es besteht auch kein Bedarf für einen Destruktor.In this example, there's no need to store the event source, and no need for a destructor.

struct Example : ExampleT<Example>
{
    Example(winrt::Windows::UI::Xaml::Controls::Button button)
    {
        m_event_revoker = button.Click(
            winrt::auto_revoke,
            [this](IInspectable const& /* sender */,
            RoutedEventArgs const& /* args */)
        {
            // ...
        });
    }

private:
    winrt::Windows::UI::Xaml::Controls::Button::Click_revoker m_event_revoker;
};

Der folgende Syntaxblock stammt aus dem Dokumentationsthema für das Ereignis ButtonBase::Click.Below is the syntax block taken from the documentation topic for the ButtonBase::Click event. Er zeigt die drei verschiedenen Registrierungs- und Widerrufsfunktionen.It shows the three different registration and revoking functions. Anhand der dritten Überladung siehst du ganz genau, welche Art von Ereignis-Revoker du deklarieren musst.You can see exactly what type of event revoker you need to declare from the third overload. Und Sie können die gleichen Arten von Delegaten sowohl an die Registrieren- als auch an die Widerrufen mit event_revoker-Überladungen übergeben.And you can pass the same kinds of delegates to both the register and the revoke with event_revoker overloads.

// Register
winrt::event_token Click(winrt::Windows::UI::Xaml::RoutedEventHandler const& handler) const;

// Revoke with event_token
void Click(winrt::event_token const& token) const;

// Revoke with event_revoker
Button::Click_revoker Click(winrt::auto_revoke_t,
    winrt::Windows::UI::Xaml::RoutedEventHandler const& handler) const;

Hinweis

Im obigen Codebeispiel ist Button::Click_revoker ein Typalias für winrt::event_revoker<winrt::Windows::UI::Xaml::Controls::Primitives::IButtonBase>.In the code example above, Button::Click_revoker is a type alias for winrt::event_revoker<winrt::Windows::UI::Xaml::Controls::Primitives::IButtonBase>. Ein ähnliches Muster gilt für alle C++/WinRT-Ereignisse.A similar pattern applies to all C++/WinRT events. Jedes Windows-Runtime-Ereignis verfügt über eine Widerrufsfunktionsüberladung, die einen Ereignis-Revoker zurückgibt, und dieser Revokertyp gehört zur Ereignisquelle.Each Windows Runtime event has a revoke function overload that returns an event revoker, and that revoker's type is a member of the event source. Nehmen wir als weiteres Beispiel das Ereignis CoreWindow::SizeChanged: Dieses Ereignis verfügt über eine Registrierungsfunktionsüberladung, die einen Wert vom Typ CoreWindow::SizeChanged_revoker zurückgibt.So, to take another example, the CoreWindow::SizeChanged event has a registration function overload that returns a value of type CoreWindow::SizeChanged_revoker.

Das Widerrufen von Handlern kann etwa in einem Seitennavigationsszenario sinnvoll sein.You might consider revoking handlers in a page-navigation scenario. Wenn du wiederholt zu einer Seite navigierst und sie wieder verlässt, kannst du beim Verlassen der Seite alle Handler widerrufen.If you're repeatedly navigating into a page and then back out, then you could revoke any handlers when you navigate away from the page. Bei Wiederverwendung der gleichen Seiteninstanz kannst du alternativ den Wert deines Tokens überprüfen und die Registrierung nur ausführen, wenn er noch nicht festgelegt ist (if (!m_token){ ... }).Alternatively, if you're re-using the same page instance, then check the value of your token and only register if it's not yet been set (if (!m_token){ ... }). Eine dritte Möglichkeit besteht darin, einen Ereignis-Revoker auf der Seite als Datenmember zu speichern.A third option is to store an event revoker in the page as a data member. Weiter unten in diesem Thema wird außerdem noch eine vierte Möglichkeit beschrieben: die Erfassung eines starken oder schwachen Verweises auf das this-Objekt in deiner Lambda-Funktion.And a fourth option, as described later in this topic, is to capture a strong or a weak reference to the this object in your lambda function.

Wenn das Registrieren des Delegaten fehlschlägtIf your auto-revoke delegate fails to register

Wenn Sie beim Registrieren eines Delegaten winrt::auto_revoke angeben und das Ergebnis eine winrt::hresult_no_interface-Ausnahme ist, bedeutet dies in der Regel, dass die Ereignisquelle schwache Verweise nicht unterstützt.If you try to specify winrt::auto_revoke when registering a delegate, and the result is a winrt::hresult_no_interface exception, then that usually means that the event source doesn't support weak references. Diese Situation tritt z. B. häufig im Windows.UI.Composition-Namespace ein.That's a common situation in the Windows.UI.Composition namespace, for example. In diesem Fall können Sie nicht den automatischen Widerruf verwenden.In this situation, you can't use the auto-revoke feature. Sie müssen die Ereignishandler manuell widerrufen.You'll have to fall back to manually revoking your event handlers.

Delegattypen für asynchrone Aktionen und VorgängeDelegate types for asynchronous actions and operations

In den obigen Beispielen wird der Delegattyp RoutedEventHandler verwendet. Es gibt aber natürlich noch viele andere Delegattypen.The examples above use the RoutedEventHandler delegate type, but there are of course many other delegate types. Asynchrone Aktionen und Vorgänge (mit und ohne Fortschritt) verfügen beispielsweise über Abschluss- und/oder Fortschrittsereignisse, die Delegaten des entsprechenden Typs erwarten.For example, asynchronous actions and operations (with and without progress) have completed and/or progress events that expect delegates of the corresponding type. So erfordert etwa das Fortschrittsereignis eines asynchronen Vorgangs mit Fortschritt (sprich: jegliche Implementierung von IAsyncOperationWithProgress) einen Delegaten vom Typ AsyncOperationProgressHandler.For example, the progress event of an asynchronous operation with progress (which is anything that implements IAsyncOperationWithProgress) requires a delegate of type AsyncOperationProgressHandler. Im Anschluss findest du ein Codebeispiel für die Erstellung eines solchen Delegattyps mit einer Lambda-Funktion.Here's a code example of authoring a delegate of that type using a lambda function. Das Beispiel veranschaulicht auch die Erstellung eines Delegaten vom Typ AsyncOperationWithProgressCompletedHandler.The example also shows how to author an AsyncOperationWithProgressCompletedHandler delegate.

#include <winrt/Windows.Foundation.h>
#include <winrt/Windows.Web.Syndication.h>

using namespace winrt;
using namespace Windows::Foundation;
using namespace Windows::Web::Syndication;

void ProcessFeedAsync()
{
    Uri rssFeedUri{ L"https://blogs.windows.com/feed" };
    SyndicationClient syndicationClient;

    auto async_op_with_progress = syndicationClient.RetrieveFeedAsync(rssFeedUri);

    async_op_with_progress.Progress(
        [](
            IAsyncOperationWithProgress<SyndicationFeed,
            RetrievalProgress> const& /* sender */,
            RetrievalProgress const& args)
        {
            uint32_t bytes_retrieved = args.BytesRetrieved;
            // use bytes_retrieved;
        });

    async_op_with_progress.Completed(
        [](
            IAsyncOperationWithProgress<SyndicationFeed,
            RetrievalProgress> const& sender,
            AsyncStatus const /* asyncStatus */)
        {
            SyndicationFeed syndicationFeed = sender.GetResults();
            // use syndicationFeed;
        });

    // or (but this function must then be a coroutine, and return IAsyncAction)
    // SyndicationFeed syndicationFeed{ co_await async_op_with_progress };
}

Wie im obigen Kommentar zu Coroutinen bereits angedeutet, ist die Verwendung von Coroutinen für dich wahrscheinlich naheliegender als die Verwendung eines Delegaten mit den Abschlussereignissen asynchroner Aktionen und Vorgänge.As the "coroutine" comment above suggests, instead of using a delegate with the completed events of asynchronous actions and operations, you'll probably find it more natural to use coroutines. Ausführlichere Informationen und Codebeispiele findest du unter Parallelität und asynchrone Vorgänge mit C++/WinRT.For details, and code examples, see Concurrency and asynchronous operations with C++/WinRT.

Hinweis

Implementiere für asynchrone Aktionen oder Vorgänge nicht mehrere Abschlusshandler.It's not correct to implement more than one completion handler for an asynchronous action or operation. Du kannst entweder einen einzelnen Delegaten für das Abschlussereignis verwenden oder co_await dafür ausführen.You can have either a single delegate for its completed event, or you can co_await it. Wenn Sie beide Abschlusshandler nutzen, schlägt der zweite fehl.If you have both, then the second will fail.

Wenn du dich für Delegaten und gegen eine Coroutine entscheidest, kannst du eine einfachere Syntax verwenden.If you stick with delegates instead of a coroutine, then you can opt for a simpler syntax.

async_op_with_progress.Completed(
    [](auto&& /*sender*/, AsyncStatus const /* args */)
{
    // ...
});

Delegattypen, die einen Wert zurückgebenDelegate types that return a value

Einige Delegattypen müssen selbst einen Wert zurückgeben.Some delegate types must themselves return a value. Ein Beispiel ist ListViewItemToKeyHandler, der eine Zeichenfolge zurückgibt.An example is ListViewItemToKeyHandler, which returns a string. Hier ist ein Beispiel für die Erstellung eines solchen Delegaten. (Beachte, dass die Lambda-Funktion einen Wert zurückgibt.)Here's an example of authoring a delegate of that type (note that the lambda function returns a value).

using namespace winrt::Windows::UI::Xaml::Controls;

winrt::hstring f(ListView listview)
{
    return ListViewPersistenceHelper::GetRelativeScrollPosition(listview, [](IInspectable const& item)
    {
        return L"key for item goes here";
    });
}

Sicheres Zugreifen auf den this-Zeiger mit einem Delegaten für die EreignisbehandlungSafely accessing the this pointer with an event-handling delegate

Wenn du ein Ereignis mit der Memberfunktion eines Objekts oder im Rahmen einer Lambda-Funktion innerhalb der Memberfunktion eines Objekts verarbeitest, musst du dir Gedanken zur relativen Lebensdauer des Ereignisempfängers (das Objekt, das das Ereignis behandelt) und der Ereignisquelle (das Objekt, das das Ereignis auslöst) machen.If you handle an event with an object's member function, or from within a lambda function inside an object's member function, then you need to think about the relative lifetimes of the event recipient (the object handling the event) and the event source (the object raising the event). Weitere Informationen und Codebeispiele findest du unter Starke und schwache Verweise in C++/WinRT.For more info, and code examples, see Strong and weak references in C++/WinRT.

Wichtige APIsImportant APIs