Not
Bu sayfaya erişim yetkilendirme gerektiriyor. Oturum açmayı veya dizinleri değiştirmeyi deneyebilirsiniz.
Bu sayfaya erişim yetkilendirme gerektiriyor. Dizinleri değiştirmeyi deneyebilirsiniz.
Önemli
Windows Uygulama SDK'sı ile geliştiriyor musunuz? Bu makalenin kodu UWP (Windows.UI.Xaml) ad alanlarını kullanır. Projeniz WinUI 3'i (Windows Uygulama SDK'sı) hedeflediyse, Microsoft.UI.Xaml yerine (ve ilgili Microsoft.UI.* ad alanlarını) ekleyin. Tam eşleme için UWP API'lerini Windows Uygulama SDK'sı'sına eşleme belgesine, ek ayrıntılar için de Kullanıcı Arabirimi Geçiş Kılavuzu'na bakın.
Bu konuda , C++/WinRT kullanarak olay işleme temsilcilerini kaydetme ve iptal etme adımları gösterilmektedir. Herhangi bir standart C++ işlev benzeri nesneyi kullanarak bir olayı işleyebilirsiniz.
Note
C++/WinRT Visual Studio Uzantısını (VSIX) ve NuGet paketini (birlikte proje şablonu ve derleme desteği sağlayan) yükleme ve kullanma hakkında bilgi için bkz. C++/WinRT için Visual Studio desteği.
Olay işleyicisi eklemek için Visual Studio kullanma
Projenize olay işleyicisi eklemenin kullanışlı bir yolu, Visual Studio XAML Tasarımcısı kullanıcı arabirimini (UI) kullanmaktır. XAML sayfanız XAML Tasarımcısı'nda açıkken, olayını işlemek istediğiniz denetimi seçin. Bu denetimin özellik sayfasında şimşek simgesine tıklayarak bu denetim tarafından kaynaklanan tüm olayları listeleyin. Ardından, işlemek istediğiniz olaya çift tıklayın; örneğin , OnClicked.
XAML Tasarımcısı, kaynak dosyalarınıza uygun olay işleyicisi işlev prototipini (ve saplama uygulamasını) ekler ve kendi uygulamanızla değiştirmeniz için hazır olur.
Note
Genellikle, olay işleyicilerinizin Midl dosyanızda (.idl ) açıklanması gerekmez. Bu nedenle, XAML Tasarımcısı Midl dosyanıza olay işleyicisi işlev prototipleri eklemez. Bunları yalnızca .h ve .cpp dosyalarınıza ekler.
Bir olayı işlemek için temsilci kaydedin
Basit bir örnek, bir düğmenin tıklama olayını işlemektir. Bunun gibi, olayı işleyecek bir üye işlevi kaydetmek için XAML biçimlendirmesi kullanmak yaygındır.
// MainPage.xaml
<Button x:Name="myButton" Click="ClickHandler">Click Me</Button>
// MainPage.h
void ClickHandler(
winrt::Windows::Foundation::IInspectable const& sender,
winrt::Microsoft::UI::Xaml::RoutedEventArgs const& args);
// MainPage.cpp
void MainPage::ClickHandler(
IInspectable const& /* sender */,
RoutedEventArgs const& /* args */)
{
myButton().Content(box_value(L"Clicked"));
}
Yukarıdaki kod, Visual Studio'daki Blank App, Packaged (WinUI 3 in Desktop) projesinden alınmıştır. Kod myButton(), adını myButton verdiğimiz Button'ı döndüren oluşturulmuş bir erişimci fonksiyonunu çağırır. Bu x:Name öğesinin adını değiştirirseniz, oluşturulan erişimci işlevinin adı da değişir.
Note
Bu durumda, olay kaynağı (olayı oluşturan nesne) myButton adlı Düğme'dir. Olay alıcısı (olayı işleyen nesne), MainPage'in bir örneğidir. Bu konunun devamında olay kaynaklarının ve olay alıcılarının yaşam ömrünü yönetme hakkında daha fazla bilgi bulabilirsiniz.
İşaretlemeyi bildirimli olarak yapmak yerine, bir olayı işlemek için bir üye işlevini kesin olarak kaydedebilirsiniz. Aşağıdaki kod örneğinde belirgin olmayabilir, ancak ButtonBase::Click çağrısının bağımsız değişkeni RoutedEventHandler temsilcisinin bir örneğidir. Bu durumda, bir nesneyi ve işaretçiden üyeye işlevi alan RoutedEventHandler oluşturucu aşırı yüklemesini kullanıyoruz.
// MainPage.cpp
MainPage::MainPage()
{
InitializeComponent();
myButton().Click({ this, &MainPage::ClickHandler });
}
Önemli
Temsilciyi kaydederken, yukarıdaki kod örneği bu işaretçinin ham değerini geçirir (geçerli nesneye işaret eder). Geçerli nesneye güçlü veya zayıf bir başvuru oluşturmayı öğrenmek için bkz. Temsilci olarak üye işlevi kullanıyorsanız.
Statik üye işlevi kullanan bir örnek aşağıda verilmiştir; daha basit söz dizimine dikkat edin.
// MainPage.h
static void ClickHandler(
winrt::Windows::Foundation::IInspectable const& sender,
winrt::Microsoft::UI::Xaml::RoutedEventArgs const& args);
// MainPage.cpp
MainPage::MainPage()
{
InitializeComponent();
myButton().Click( MainPage::ClickHandler );
}
void MainPage::ClickHandler(
IInspectable const& /* sender */,
RoutedEventArgs const& /* args */) { ... }
RoutedEventHandler oluşturmanın başka yolları da vardır. Aşağıda RoutedEventHandler belge konusundan alınan söz dizimi bloğu yer almaktadır (web sayfasının sağ üst köşesindeki Dil açılan listesindeN C++/WinRT'yi seçin). Farklı oluşturuculara dikkat edin: biri bir lambda alır; bir diğeri bağımsız bir işlev alır; bir başkası da (yukarıda kullandığımız) bir nesne ve bir üye işlev işaretçisi alır.
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);
/* ... other constructors ... */
void operator()(winrt::Windows::Foundation::IInspectable const& sender,
winrt::Microsoft::UI::Xaml::RoutedEventArgs const& e) const;
};
İşlev çağrısı işlecinin söz dizimini görmek de yararlıdır. Temsilcinizin parametrelerinin ne olması gerektiğini belirtir. Gördüğünüz gibi, bu durumda işlev çağrısı işleci söz dizimi MainPage::ClickHandler parametrelerimizle eşleşir.
Note
Belirli bir olay için, temsilcisinin ayrıntılarını ve bu temsilcinin parametrelerini bulmak için önce olayın belge konusuna gidin. Örnek olarak UIElement.KeyDown olayını ele alalım. Bu konuya gidin ve Dil açılır listesinden C++/WinRT'yi seçin. Konunun başındaki söz dizimi bloğunda bunu görürsünüz.
// Register
event_token KeyDown(KeyEventHandler const& handler) const;
Bu bilgi, UIElement.KeyDown olayının (şu anda ele aldığımız konu) KeyEventHandler temsilci türüne sahip olduğunu gösterir; çünkü bu olay türüyle bir temsilci kaydettiğinizde geçirdiğiniz tür budur. Bu nedenle, şimdi bu KeyEventHandler temsilci türüyle ilgili konudaki bağlantıyı izleyin. Burada söz dizimi bloğu bir işlev çağrısı işleci içerir. Yukarıda da belirtildiği gibi, temsilcinizin parametrelerinin ne olması gerektiğini belirtir.
void operator()(
winrt::Windows::Foundation::IInspectable const& sender,
winrt::Microsoft::UI::Xaml::Input::KeyRoutedEventArgs const& e) const;
Gördüğünüz gibi, temsilcinin gönderen olarak IInspectable ve args olarak KeyRoutedEventArgs sınıfını örneğini kabul edecek şekilde bildirilmesi gerekir.
Başka bir örnek almak için Popup.Closed olayına bakalım. Temsilci türü EventHandler<IInspectable'dır>. Yani, temsilciniz gönderen olarak bir IInspectable ve argüman olarak başka bir IInspectable kabul eder (çünkü bu, EventHandler'ın tür parametresidir).
Olay işleyicinizde çok fazla iş yapmıyorsanız üye işlevi yerine lambda işlevini kullanabilirsiniz. Yine, aşağıdaki kod örneğinden açıkça belli olmayabilir, ancak routedEventHandler temsilcisi, yukarıda ele aldığımız işlev çağrısı işlecinin söz dizimi ile eşleşmesi gereken bir lambda işlevinden oluşturulmakta.
MainPage::MainPage()
{
InitializeComponent();
myButton().Click([this](IInspectable const& /* sender */, RoutedEventArgs const& /* args */)
{
myButton().Content(box_value(L"Clicked"));
});
}
Temsilcinizi oluştururken biraz daha açık olabilirsiniz. Örneğin, bunu başkalarıyla paylaşmak veya birden fazla kez kullanmak istiyorsanız.
MainPage::MainPage()
{
InitializeComponent();
auto click_handler = [](IInspectable const& sender, RoutedEventArgs const& /* args */)
{
sender.as<winrt::Microsoft::UI::Xaml::Controls::Button>().Content(box_value(L"Clicked"));
};
myButton().Click(click_handler);
AnotherButton().Click(click_handler);
}
Kayıtlı temsilciyi iptal etme
Bir temsilciyi kaydettiğinizde, genellikle size bir belirteç döndürülür. Daha sonra temsilcinizi iptal etmek için bu belirteci kullanabilirsiniz; , temsilcinin olaydan kaydının silindiği ve olayın yeniden tetiklenmesi durumunda çağrılmayacağı anlamına gelir.
Kolaylık olması açısından, yukarıdaki kod örneklerinden hiçbiri bunun nasıl yapılacağını göstermedi. Ancak bu sonraki kod örneği, belirteci yapının özel veri üyesinde depolar ve yıkıcıdaki işleyicisini iptal eder.
struct Example : ExampleT<Example>
{
Example(winrt::Microsoft::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::Microsoft::UI::Xaml::Controls::Button m_button;
winrt::event_token m_token;
};
Yukarıdaki örnekte olduğu gibi güçlü bir başvuru yerine, düğmeye zayıf bir başvuru depolayabilirsiniz (bkz. C++/WinRT'de güçlü ve zayıf başvurular).
Note
Olay kaynağı olaylarını zaman uyumlu bir şekilde yükselttiğinde, işleyicinizi iptal edebilir ve daha fazla olay almayacağınızdan emin olabilirsiniz. Ancak zaman uyumsuz olaylar için, iptal işleminden sonra bile (ve özellikle yıkıcı içinde iptal ederken), yok etme işlemi başladıktan sonra bir uçuş içi olay nesnenize ulaşabilir. Yok edilmeden önce aboneliği kaldırabileceğiniz bir yer bulmak sorunu hafifletebilir veya sağlam bir çözüm için bkz. Olay işleme temsilcisiyle bu işaretçiye güvenli bir şekilde erişme.
Alternatif olarak, bir temsilci kaydederken, bir olay geri alıcısı (türü winrt::event_revoker olan) istemek için winrt::auto_revoke belirtebilirsiniz (bu, winrt::auto_revoke_t türünde bir değerdir). Olay iptal edicisi sizin için olay kaynağına (olayı oluşturan nesne) zayıf bir başvuru barındırır. event_revoker::revoke üye işlevini çağırarak el ile iptal edebilirsiniz; ancak olay iptal edici, kapsamın dışına çıktığında işlevin kendisini otomatik olarak çağırır. revoke işlevi, olay kaynağının hala var olup olmadığını denetler ve varsa temsilcinizi iptal eder. Bu örnekte, olay kaynağını depolamaya ve yok ediciye gerek yoktur.
struct Example : ExampleT<Example>
{
Example(winrt::Microsoft::UI::Xaml::Controls::Button button)
{
m_event_revoker = button.Click(
winrt::auto_revoke,
[this](IInspectable const& /* sender */,
RoutedEventArgs const& /* args */)
{
// ...
});
}
private:
winrt::Microsoft::UI::Xaml::Controls::Button::Click_revoker m_event_revoker;
};
ButtonBase::Click olayının belge konu başlığından alınan söz dizimi bloğu aşağıdadır. Üç farklı kayıt ve iptal etme işlevini gösterir. Üçüncü aşırı yüklemeden, tanımlamanız gereken olay geri alma nesnesinin tam olarak hangi türde olduğunu görebilirsiniz. Ayrıca, aynı tür temsilcileri hem register hem de revoke with event_revoker aşırı yüklemelerine geçirebilirsiniz.
// Register
winrt::event_token Click(winrt::Microsoft::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::Microsoft::UI::Xaml::RoutedEventHandler const& handler) const;
Note
Yukarıdaki kod örneğinde, Button::Click_revoker için winrt::event_revoker<winrt::Microsoft::UI::Xaml::Controls::Primitives::IButtonBase>bir tür diğer adıdır. Benzer bir desen tüm C++/WinRT olayları için geçerlidir. Windows Çalışma Zamanı’daki her olayın, bir olay iptal edicisi döndüren revoke işlevinin bir aşırı yüklemesi vardır ve bu iptal edicinin türü olay kaynağının bir üyesidir. Bu nedenle, başka bir örnek almak için Window::SizeChanged olayının Window::SizeChanged_revoker türünde bir değer döndüren bir kayıt işlevi aşırı yüklemesi vardır.
Bir sayfa gezinti senaryosunda işleyicileri iptal etmeyi düşünebilirsiniz. Bir sayfaya tekrar tekrar gidip sonra geri dönüyorsanız, sayfadan ayrıldığınızda işleyicileri kaldırabilirsiniz. Alternatif olarak, aynı sayfa örneğini yeniden kullanıyorsanız, belirtecinizin değerini denetleyin ve yalnızca henüz ayarlanmamışsa kaydı gerçekleştirin (if (!m_token){ ... }). Üçüncü bir seçenek de sayfada bir olay iptal ediciyi veri üyesi olarak depolamaktır. Bu konunun ilerleyen bölümlerinde açıklandığı gibi dördüncü bir seçenek de lambda işlevinizdeki bu nesneye güçlü veya zayıf bir başvuru yakalamaktır.
Otomatik iptal temsilciniz kaydedilemezse
Bir temsilciyi kaydederken winrt::auto_revoke belirtmeye çalışırsanız ve bunun sonucunda winrt::hresult_no_interface özel durumu oluşursa, bu genellikle olay kaynağının zayıf referansları desteklemediği anlamına gelir. Bu, örneğin Microsoft.UI.Composition ad alanında yaygın bir durumdur. Bu durumda otomatik iptal özelliğini kullanamazsınız. Olay işleyicilerinizi manuel olarak kaldırmak zorunda kalacaksınız.
Zaman uyumsuz eylemler ve işlemler için temsilci türleri
Yukarıdaki örneklerde RoutedEventHandler temsilci türü kullanılır, ancak elbette başka birçok temsilci türü vardır. Örneğin, zaman uyumsuz eylemler ve işlemler (ilerleme ile ve ilerleme olmadan) ilgili türde temsilciler bekleyen olayları ve/veya ilerleme olaylarını tamamlamış olur. Örneğin, ilerleme içeren bir asenkron işlemin ilerleme olayı (yani IAsyncOperationWithProgress uygulayan her şey) AsyncOperationProgressHandler türünde bir temsilci gerektirir. Aşağıda, lambda işlevi kullanarak bu tür bir temsilci yazmanın kod örneği verilmiştır. Örnekte ayrıca AsyncOperationWithProgressCompletedHandler temsilcisinin nasıl yazıldığı da gösterilmektedir .
#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 };
}
Yukarıdaki "eş yordam" yorumunun da gösterdiği gibi, zaman uyumsuz eylem ve işlemlerin tamamlanma olaylarında bir delege kullanmak yerine, muhtemelen eş yordamları kullanmayı daha doğal bulacaksınız. Ayrıntılar ve kod örnekleri için bkz. C++/WinRT ile eşzamanlılık ve zaman uyumsuz işlemler.
Note
Zaman uyumsuz bir eylem veya işlem için birden fazla tamamlama işleyicisi uygulamak doğru değildir. Tamamlanmış olayı için tek bir temsilciniz olabilir veya bunu yapabilirsiniz co_await . her ikisine de sahipseniz, ikincisi başarısız olur.
Bir eş yordam yerine temsilcilerle birlikte çalışırsanız, daha basit bir söz dizimi seçebilirsiniz.
async_op_with_progress.Completed(
[](auto&& /*sender*/, AsyncStatus const /* args */)
{
// ...
});
Değer döndüren temsilci türleri
Bazı temsilci türlerinin kendileri bir değer döndürmelidir. Bir dize döndüren ListViewItemToKeyHandler örneğidir. Bu tür bir temsilci yazma örneği aşağıda verilmiştir (lambda işlevinin bir değer döndürdüğüne dikkat edin).
using namespace winrt::Microsoft::UI::Xaml::Controls;
winrt::hstring f(ListView listview)
{
return ListViewPersistenceHelper::GetRelativeScrollPosition(listview, [](IInspectable const& item)
{
return L"key for item goes here";
});
}
Olay işleme temsilcisiyle bu işaretçiye güvenli bir şekilde erişme
Bir olayı nesnenin üye işleviyle veya nesnenin üye işlevinin içindeki lambda işlevinin içinden işlerseniz, olay alıcısının göreli yaşam sürelerini (olayı işleyen nesne) ve olay kaynağını (olayı yükselten nesne) düşünmeniz gerekir. Daha fazla bilgi ve kod örnekleri için bkz. C++/WinRT'de güçlü ve zayıf başvurular.
Önemli API'ler
- winrt::auto_revoke_t işaretçi yapısı
- winrt::implements::get_weak işlevi
- winrt::implements::get_strong işlevi
İlgili konular
Windows developer