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.
Bu konu, C++/WinRTkullanarak olay işleme temsilcilerini kaydetme ve iptal etme
Uyarı
C++/WinRT Visual Studio Uzantısı (VSIX) ve NuGet paketini (birlikte proje şablonu ve derleme desteği sağlayan) yükleme ve kullanma hakkında bilgi için bkz. C++/WinRTiç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'da 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,
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.
Uyarı
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. Sadece onları .h ve .cpp dosyalarınıza ekler.
Bir etkinliği yönetmek için bir delege kaydetme
Basit bir örnek, bir düğmenin tıklama olayını işlemektir. Olayı işlemek için bir üye işlevi kaydetmek için XAML işaretlemesi kullanmak normaldir, örneğin.
// 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"));
}
Yukarıdaki kod Visual Studio'daki Boş Uygulama (C++/WinRT) projesinden alınmıştır. kod myButton(), bizim myButtonolarak adlandırdığımız Düğme'yi döndüren oluşturulmuş bir erişimci fonksiyonu çağırır. Eğer bu x:Name öğesinin 'sunu değiştirirseniz, oluşturulan erişimci işlevin adı da değişir.
Uyarı
Bu durumda, olay kaynağı (olayı oluşturan nesne)
İş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 nesne 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çisini (geçerli nesneye işaret eden) ham bir
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::Windows::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,
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::Windows::UI::Xaml::RoutedEventArgs const& e) const;
};
Fonksiyon çağrısı operatörünün söz dizimini görmek de faydalı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.
Uyarı
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. Konuya gidin ve Dil açılır menüsünden C++/WinRT seçeneğini 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 bilgiler, UIElement.KeyDown olayının (üzerinde olduğumuz konu) KeyEventHandlertüründe bir temsilciye sahip olduğunu söyler, çünkü bu olay türünde 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::Windows::UI::Xaml::Input::KeyRoutedEventArgs const& e) const;
Gördüğünüz gibi, temsilcinin gönderen olarak IInspectable alması ve KeyRoutedEventArgs sınıfının bir örneğinin args olarak bildirilmesi gerekir.
Başka bir örnek almak için Popup.Closed olayınagöz atalım. Temsilci türü EventHandler<IInspectable>' dir. Bu nedenle, temsilciniz gönderen olarak bir IInspectable ve başka bir IInspectable (çünkü bu, EventHandlertür parametresidir) args olarak alır.
Olay işleyicinizde çok fazla iş yapmıyorsanız üye işlevi yerine lambda işlevini kullanabilirsiniz. Yine aşağıdaki kod örneğinde belirgin olmayabilir, ancak bir RoutedEventHandler temsilcisi, yukarıda ele aldığımız işlev çağrısı işlecinin söz dizimini eşleştirmesi 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 etrafında dolaştırmak veya birden fazla kez kullanmak istiyorsanız.
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);
}
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::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;
};
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).
Uyarı
Olay kaynağı olaylarını senkron şekilde yükselttiğinde, işleyicinizi devre dışı bırakabilir 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 abonelikten çıkmak için bir yer bulmak sorunu hafifletebilir veya sağlam bir çözüm için
Alternatif olarak, bir temsilciyi kaydederken, winrt::auto_revoke (bu, winrt::auto_revoke_ttüründe bir değerdir) belirterek, bir olay iptal edici (winrt::event_revokertüründen) talep edebilirsiniz. Olay iptal edicisi, sizin için olay kaynağına (olayı oluşturan nesne) zayıf bir referans barındırır. event_revoker::revoke üye işlevini çağırarak manuel olarak iptal edebilirsiniz; ancak event revoker, kapsamın dışına çıktığında bu işlevi otomatik olarak kendi kendine ç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::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;
};
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 bildirmeniz gereken olay iptal edici türünü tam olarak görebilirsiniz. Aynı türde temsilcileri hem
// 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;
Uyarı
Yukarıdaki kod örneğinde, Button::Click_revoker için winrt::event_revoker<winrt::Windows::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. Her bir Windows Çalışma Zamanı olayının, bir olay iptal edici nesne döndüren bir iptal işlevi aşırı yüklemesi vardır ve iptal edicinin türü olay kaynağının bir üyesidir. Bu nedenle, başka bir örnek almak gerekirse, CoreWindow::SizeChanged olayı, CoreWindow::SizeChanged_revokertüründe bir değer döndüren bir aşırı yüklenmiş kayıt işlevine sahiptir.
Bir sayfa gezinti senaryosunda işleyicileri iptal etmeyi düşünebilirsiniz. Bir sayfaya tekrar tekrar gidip geri çıkıyorsanız, sayfadan çıktığınızda işleyicileri iptal edebilirsiniz. Alternatif olarak, aynı sayfa örneğini tekrar kullanıyorsanız, belirtecinizin değerini kontrol edin ve yalnızca henüz ayarlanmadıysa kaydedin (if (!m_token){ ... }). Üçüncü bir seçenek de sayfada bir olay iptal ediciyi veri üyesi olarak depolamaktır. Dördüncü bir seçenek, bu konunun ilerleyen bölümlerinde açıklandığı gibi, lambda işlevinizdeki bu nesnesine güçlü ya da zayıf bir başvuru yakalamaktır.
Otomatik iptal temsilciniz kaydedilemezse
Temsilci kaydederken winrt::auto_revoke belirtmeye çalışırsanız ve sonuç winrt::hresult_no_interface özel durumu oluşuyorsa, bu genellikle olay kaynağının zayıf başvuruları desteklemediği anlamına gelir. Bu, örneğin Windows.UI.Composition ad alanında sık karşılaşılan bir durumdır. Bu durumda otomatik iptal özelliğini kullanamazsınız. Etkinlik işleyicilerinizi manuel olarak iptal etmeye başvurmanız gerekecek.
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, uygulayan herhangi bir asenkron işlemin ilerleme olayı (IAsyncOperationWithProgress), türünde bir AsyncOperationProgressHandlertemsilcisi 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" açıklamasının da belirttiği gibi, asenkron eylem ve işlemlerin tamamlanmış olayları için bir temsilci 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.
Uyarı
Zaman uyumsuz bir eylem veya işlem için birden fazla tamamlama işleyicisi uygulamak doğru değildir. Tamamlanmış olay için ya tek bir temsilciniz olabilir ya da onu co_await edebilirsiniz. her ikisine de sahipseniz, ikincisi başarısız olur.
Temsilcilerle birlikte çalışmayı tercih ederseniz, bir eş yordam yerine 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ürleri bizzat bir değer döndürmelidir. Bir dize döndüren ListViewItemToKeyHandler
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";
});
}
Olay işleme temsilcisi kullanarak bu işaretçisine 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