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, Windows Çalışma Zamanı components with C++/WinRT konusunda nasıl oluşturulacağı gösterilen Windows Çalışma Zamanı bileşeni ile bu bileşeni kullanan uygulamayı temel alır.
Bu konunun eklediği yeni özellikler aşağıdadır.
- Termometre çalışma zamanı sınıfını, sıcaklığı donma durumunun altına indiğinde bir olay oluşturacak şekilde güncelleştirin.
- Termometre çalışma zamanı sınıfını kullanan Core Uygulamasını bu olayı işleyecek şekilde güncelleştirin.
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.
Önemli
C++/WinRT ile çalışma zamanı sınıflarını kullanma ve yazma hakkında bilginizi destekleyen temel kavramlar ve terimler için bkz. C++/WinRT ile API'leri kullanma ve C++/WinRT ile API'leri yazma.
ThermometerWRC ve ThermometerCoreApp oluşturma
Kodu oluşturup çalıştırabilmek için bu konuda gösterilen güncelleştirmelerle birlikte ilerlemek istiyorsanız, ilk adım C++/WinRT ile Windows Çalışma Zamanı bileşenleri konusunda izlenecek yolu izlemektir. Bunu yaptığınızda ThermometerWRC Windows Çalışma Zamanı bileşenine ve bunu kullanan ThermometerCoreApp Core Uygulamasına sahip olursunuz.
ThermometerWRC'yi olay oluşturacak şekilde güncelleştirme
Aşağıdaki liste gibi görünecek şekilde güncelleştirin Thermometer.idl . Tek duyarlıklı kayan noktalı sayı bağımsız değişkeniyle temsilci türü EventHandler olan bir olayı bu şekilde bildirebilirsiniz.
// Thermometer.idl
namespace ThermometerWRC
{
runtimeclass Thermometer
{
Thermometer();
void AdjustTemperature(Single deltaFahrenheit);
event Windows.Foundation.EventHandler<Single> TemperatureIsBelowFreezing;
};
}
Dosyayı kaydedin. Proje mevcut hâliyle derlemeyi başarıyla tamamlamayacaktır, ancak \ThermometerWRC\ThermometerWRC\Generated Files\sources\Thermometer.h ve Thermometer.cpp saplama dosyalarının güncelleştirilmiş sürümlerini oluşturmak için yine de şimdi bir derleme gerçekleştirin. Bu dosyalarda artık TemperatureIsBelowFreezing olayının taslak uygulamalarını görebilirsiniz. C++/WinRT'de, IDL tarafından bildirilen bir olay aşırı yüklenmiş işlevler kümesi olarak uygulanır (bir özelliğin aşırı yüklenmiş get ve set işlevleri çifti olarak uygulanmasına benzer). Bir aşırı yükleme, bir temsilcinin kaydedilmesini alır ve bir belirteç ( winrt::event_token) döndürür. Diğeri bir belirteç alır ve ilişkili temsilcinin kaydını iptal eder.
Şimdi Thermometer.h ile Thermometer.cpp öğelerini açın ve Thermometer çalışma zamanı sınıfının uygulamasını güncelleştirin.
Thermometer.h içine, iki aşırı yüklenmiş TemperatureIsBelowFreezing işlevinin yanı sıra bu işlevlerin uygulanmasında kullanılacak özel bir olay veri üyesi ekleyin.
// Thermometer.h
...
namespace winrt::ThermometerWRC::implementation
{
struct Thermometer : ThermometerT<Thermometer>
{
...
winrt::event_token TemperatureIsBelowFreezing(Windows::Foundation::EventHandler<float> const& handler);
void TemperatureIsBelowFreezing(winrt::event_token const& token) noexcept;
private:
winrt::event<Windows::Foundation::EventHandler<float>> m_temperatureIsBelowFreezingEvent;
...
};
}
...
Yukarıda görebileceğiniz gibi, bir olay winrt::event yapısı şablonu tarafından temsil edilir ve belirli bir temsilci türüyle parametrelendirilir (kendisi bir args türü tarafından parametreleştirilebilir).
Thermometer.cpp içinde, iki aşırı yüklemeli TemperatureIsBelowFreezing işlevini gerçekleştirin.
// Thermometer.cpp
...
namespace winrt::ThermometerWRC::implementation
{
winrt::event_token Thermometer::TemperatureIsBelowFreezing(Windows::Foundation::EventHandler<float> const& handler)
{
return m_temperatureIsBelowFreezingEvent.add(handler);
}
void Thermometer::TemperatureIsBelowFreezing(winrt::event_token const& token) noexcept
{
m_temperatureIsBelowFreezingEvent.remove(token);
}
void Thermometer::AdjustTemperature(float deltaFahrenheit)
{
m_temperatureFahrenheit += deltaFahrenheit;
if (m_temperatureFahrenheit < 32.f) m_temperatureIsBelowFreezingEvent(*this, m_temperatureFahrenheit);
}
}
Note
Otomatik olay iptal edicinin ne olduğuna ilişkin ayrıntılar için bkz. Kayıtlı temsilciyi iptal etme. Otomatik olay iptal edici uygulamasını etkinliğiniz için ücretsiz alırsınız. Başka bir deyişle, olay geri alıcısı için aşırı yüklemeyi uygulamanıza gerek yoktur; bunu sizin için C++/WinRT projeksiyonu sağlar.
Diğer aşırı yüklemeler (kayıt ve manuel geri alma aşırı yüklemeleri) projeksiyona dahil edilmemiştir. Bunun nedeni, bunları senaryonuz için en uygun şekilde uygulama esnekliği sağlamaktır. Bu uygulamalarda gösterildiği gibi event::add ve event::remove çağrısı verimli ve eşzamanlılık/iş parçacığı güvenli varsayılanıdır. Ancak çok fazla sayıda olayınız varsa, her biri için bir olay alanı istemeyebilir, bunun yerine bir tür seyrek uygulama tercih edebilirsiniz.
Ayrıca yukarıda AdjustTemperature işlevinin uygulanmasının sıcaklık donma altına girerse TemperatureIsBelowFreezing olayını yükseltecek şekilde güncelleştirildiğini görebilirsiniz.
Olayı işlemek için ThermometerCoreApp'i güncelleştirme
ThermometerCoreApp projesinde, içindeApp.cpp, bir olay işleyicisini kaydetmek için kodda aşağıdaki değişiklikleri yapın ve ardından sıcaklığın donma durumunun altına düşmesine neden olun.
WINRT_ASSERT bir makro tanımıdır ve _ASSERTE genişletilir.
struct App : implements<App, IFrameworkViewSource, IFrameworkView>
{
winrt::event_token m_eventToken;
...
void Initialize(CoreApplicationView const &)
{
m_eventToken = m_thermometer.TemperatureIsBelowFreezing([](const auto &, float temperatureFahrenheit)
{
WINRT_ASSERT(temperatureFahrenheit < 32.f); // Put a breakpoint here.
});
}
...
void Uninitialize()
{
m_thermometer.TemperatureIsBelowFreezing(m_eventToken);
}
...
void OnPointerPressed(IInspectable const &, PointerEventArgs const & args)
{
m_thermometer.AdjustTemperature(-1.f);
...
}
...
};
OnPointerPressed yöntemindeki değişikliği unutmayın. Şimdi, pencereye her tıkladığınızda termometrenin sıcaklığından 1 derece Fahrenheit çıkarırsınız . Şimdi de uygulama, sıcaklık donma durumunun altına indiğinde ortaya çıkan olayı işlemeye devam ediyor. Olayın beklendiği gibi yükseltildiğini göstermek için TemperatureIsBelowFreezing olayını işleyen lambda ifadesinin içine bir kesme noktası koyun, uygulamayı çalıştırın ve pencerenin içine tıklayın.
ABI genelinde parametreli temsilciler
Olayınıza bir uygulama ikili arabirimi (ABI) üzerinden — örneğin bir bileşen ile onu kullanan uygulama arasında — erişilmesi gerekiyorsa, olayınızın bir Windows Çalışma Zamanı temsilci türü kullanması gerekir. Yukarıdaki örnek, Windows::Foundation::EventHandler<T> Windows Çalışma Zamanı temsilci türünü kullanır. TypedEventHandler<TSender, TResult>, Windows Çalışma Zamanı temsilci türünün başka bir örneğidir.
Bu iki temsilci türü için tür parametrelerinin ABI sınırını geçmesi gerektiğinden, tür parametreleri de Windows Çalışma Zamanı türleri olmalıdır. Buna Windows çalışma zamanı sınıfları, üçüncü taraf çalışma zamanı sınıfları ve sayılar ve dizeler gibi temel türler dahildir. Derleyici, bu kısıtlamayı unutursanız "T WinRT türü olmalıdır" hatasıyla size yardımcı olur.
Aşağıda kod dökümleri biçiminde bir örnek verilmiştir. Bu konuda daha önce oluşturduğunuz ThermometerWRC ve ThermometerCoreApp projeleriyle başlayın ve bu projelerdeki kodu bu listelerdeki kod gibi görünecek şekilde düzenleyin.
Bu ilk liste ThermometerWRC projesine yöneliktir. Aşağıda gösterildiği gibi ThermometerWRC.idl öğesini düzenledikten sonra projeyi derleyin ve ardından, daha önce Thermometer.h ile .cpp için yaptığınız gibi, Generated Files klasöründen MyEventArgs.h ve .cpp öğelerini projeye kopyalayın. Her iki dosyadan da static_assert öğesini silmeyi unutmayın.
// ThermometerWRC.idl
namespace ThermometerWRC
{
[default_interface]
runtimeclass MyEventArgs
{
Single TemperatureFahrenheit{ get; };
}
[default_interface]
runtimeclass Thermometer
{
...
event Windows.Foundation.EventHandler<ThermometerWRC.MyEventArgs> TemperatureIsBelowFreezing;
...
};
}
// MyEventArgs.h
#pragma once
#include "MyEventArgs.g.h"
namespace winrt::ThermometerWRC::implementation
{
struct MyEventArgs : MyEventArgsT<MyEventArgs>
{
MyEventArgs() = default;
MyEventArgs(float temperatureFahrenheit);
float TemperatureFahrenheit();
private:
float m_temperatureFahrenheit{ 0.f };
};
}
// MyEventArgs.cpp
#include "pch.h"
#include "MyEventArgs.h"
#include "MyEventArgs.g.cpp"
namespace winrt::ThermometerWRC::implementation
{
MyEventArgs::MyEventArgs(float temperatureFahrenheit) : m_temperatureFahrenheit(temperatureFahrenheit)
{
}
float MyEventArgs::TemperatureFahrenheit()
{
return m_temperatureFahrenheit;
}
}
// Thermometer.h
...
struct Thermometer : ThermometerT<Thermometer>
{
...
winrt::event_token TemperatureIsBelowFreezing(Windows::Foundation::EventHandler<ThermometerWRC::MyEventArgs> const& handler);
...
private:
winrt::event<Windows::Foundation::EventHandler<ThermometerWRC::MyEventArgs>> m_temperatureIsBelowFreezingEvent;
...
}
...
// Thermometer.cpp
#include "MyEventArgs.h"
...
winrt::event_token Thermometer::TemperatureIsBelowFreezing(Windows::Foundation::EventHandler<ThermometerWRC::MyEventArgs> const& handler) { ... }
...
void Thermometer::AdjustTemperature(float deltaFahrenheit)
{
m_temperatureFahrenheit += deltaFahrenheit;
if (m_temperatureFahrenheit < 32.f)
{
auto args = winrt::make_self<winrt::ThermometerWRC::implementation::MyEventArgs>(m_temperatureFahrenheit);
m_temperatureIsBelowFreezingEvent(*this, *args);
}
}
...
Bu liste ThermometerCoreApp projesine yöneliktir.
// App.cpp
...
void Initialize(CoreApplicationView const&)
{
m_eventToken = m_thermometer.TemperatureIsBelowFreezing([](const auto&, ThermometerWRC::MyEventArgs args)
{
float degrees = args.TemperatureFahrenheit();
WINRT_ASSERT(degrees < 32.f); // Put a breakpoint here.
});
}
...
ABI genelinde basit sinyaller
Olayınızla birlikte herhangi bir parametre ya da bağımsız değişken geçirmeniz gerekmiyorsa, kendi basit Windows Çalışma Zamanı temsilci türünüzü tanımlayabilirsiniz. Aşağıdaki örnekte Thermometer çalışma zamanı sınıfının daha basit bir sürümü gösterilmektedir. SignalDelegate adlı bir temsilci türü bildirir ve bunu parametreli bir olay yerine sinyal türü olayı oluşturmak için kullanır.
// ThermometerWRC.idl
namespace ThermometerWRC
{
delegate void SignalDelegate();
runtimeclass Thermometer
{
Thermometer();
event ThermometerWRC.SignalDelegate SignalTemperatureIsBelowFreezing;
void AdjustTemperature(Single value);
};
}
// Thermometer.h
...
namespace winrt::ThermometerWRC::implementation
{
struct Thermometer : ThermometerT<Thermometer>
{
...
winrt::event_token SignalTemperatureIsBelowFreezing(ThermometerWRC::SignalDelegate const& handler);
void SignalTemperatureIsBelowFreezing(winrt::event_token const& token);
void AdjustTemperature(float deltaFahrenheit);
private:
winrt::event<ThermometerWRC::SignalDelegate> m_signal;
float m_temperatureFahrenheit{ 0.f };
};
}
// Thermometer.cpp
...
namespace winrt::ThermometerWRC::implementation
{
winrt::event_token Thermometer::SignalTemperatureIsBelowFreezing(ThermometerWRC::SignalDelegate const& handler)
{
return m_signal.add(handler);
}
void Thermometer::SignalTemperatureIsBelowFreezing(winrt::event_token const& token)
{
m_signal.remove(token);
}
void Thermometer::AdjustTemperature(float deltaFahrenheit)
{
m_temperatureFahrenheit += deltaFahrenheit;
if (m_temperatureFahrenheit < 32.f)
{
m_signal();
}
}
}
// App.cpp
struct App : implements<App, IFrameworkViewSource, IFrameworkView>
{
ThermometerWRC::Thermometer m_thermometer;
winrt::event_token m_eventToken;
...
void Initialize(CoreApplicationView const &)
{
m_eventToken = m_thermometer.SignalTemperatureIsBelowFreezing([] { /* ... */ });
}
...
void Uninitialize()
{
m_thermometer.SignalTemperatureIsBelowFreezing(m_eventToken);
}
...
void OnPointerPressed(IInspectable const &, PointerEventArgs const & args)
{
m_thermometer.AdjustTemperature(-1.f);
...
}
...
};
Proje içinde parametreli temsilciler, basit sinyaller ve geri çağırmalar
bu olayların Windows Çalışma Zamanı türleriyle sınırlı olmadığı Visual Studio projenizin içindeki olaylara (ikili dosyalar arasında değil) ihtiyacınız varsa winrt::event<Delegate> sınıf şablonunu kullanmaya devam edebilirsiniz. Yalnızca, gerçek bir Windows Çalışma Zamanı temsilci türü yerine winrt::delegate kullanın; çünkü winrt::delegate Windows Çalışma Zamanı olmayan parametreleri de destekler.
Aşağıdaki örnekte ilk olarak parametre almayan bir temsilci imzası (temelde basit bir sinyal) ve ardından dize alan bir imza gösterilmektedir.
winrt::event<winrt::delegate<>> signal;
signal.add([] { std::wcout << L"Hello, "; });
signal.add([] { std::wcout << L"World!" << std::endl; });
signal();
winrt::event<winrt::delegate<std::wstring>> log;
log.add([](std::wstring const& message) { std::wcout << message.c_str() << std::endl; });
log.add([](std::wstring const& message) { Persist(message); });
log(L"Hello, World!");
Etkinliğe istediğiniz kadar abone olan temsilciyi nasıl ekleyebileceğinize dikkat edin. Ancak, bir olayla ilişkili bazı ek yük vardır. İhtiyacınız olan tek şey, yalnızca tek bir abone olan bir temsilciyle basit bir geri çağırma ise, winrt::delegate<... T>'i tek başına kullanabilirsiniz.
winrt::delegate<> signalCallback;
signalCallback = [] { std::wcout << L"Hello, World!" << std::endl; };
signalCallback();
winrt::delegate<std::wstring> logCallback;
logCallback = [](std::wstring const& message) { std::wcout << message.c_str() << std::endl; }f;
logCallback(L"Hello, World!");
Olayların ve temsilcilerin bir proje içinde dahili olarak kullanıldığı bir C++/CX kod tabanından geçiş yapıyorsanız, winrt::delegate bu deseni C++/WinRT içinde yeniden oluşturmanıza yardımcı olur.
Ertelenebilir olaylar
Windows Çalışma Zamanı'ta yaygın bir örüntü ertelenebilir olaydır. Olay işleyicisi, olay bağımsız değişkeninin GetDeferral yöntemini çağırarak bir erteleme alır. Bunun yapılması, olay kaynağına etkinlik sonrası etkinliklerin erteleme işlemi tamamlanana kadar ertelenmesi gerektiğini gösterir. Bu, olay işleyicinin bir olaya yanıt olarak zaman uyumsuz eylemler gerçekleştirmesine olanak tanır.
winrt::d eferrable_event_args yapı şablonu, Windows Çalışma Zamanı erteleme desenini uygulamaya (üretmeye) yönelik bir yardımcı sınıftır. İşte bir örnek.
// Widget.idl
namespace Sample
{
runtimeclass WidgetStartingEventArgs
{
Windows.Foundation.Deferral GetDeferral();
Boolean Cancel;
};
runtimeclass Widget
{
event Windows.Foundation.TypedEventHandler<
Widget, WidgetStartingEventArgs> Starting;
};
}
// Widget.h
namespace winrt::Sample::implementation
{
struct Widget : WidgetT<Widget>
{
Widget() = default;
event_token Starting(Windows::Foundation::TypedEventHandler<
Sample::Widget, Sample::WidgetStartingEventArgs> const& handler)
{
return m_starting.add(handler);
}
void Starting(event_token const& token) noexcept
{
m_starting.remove(token);
}
private:
event<Windows::Foundation::TypedEventHandler<
Sample::Widget, Sample::WidgetStartingEventArgs>> m_starting;
};
struct WidgetStartingEventArgs : WidgetStartingEventArgsT<WidgetStartingEventArgs>,
deferrable_event_args<WidgetStartingEventArgs>
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
{
bool Cancel() const noexcept { return m_cancel; }
void Cancel(bool value) noexcept { m_cancel = value; }
bool m_cancel = false;
};
}
Olay alıcısı ertelenebilir olay desenini şu şekilde tüketir.
// EventRecipient.h
widget.Starting([](auto sender, auto args) -> fire_and_forget
{
auto deferral = args.GetDeferral();
if (!co_await CanWidgetStartAsync(sender))
{
// Do not allow the widget to start.
args.Cancel(true);
}
deferral.Complete();
});
Olay kaynağının uygulayıcısı (üreticisi) olarak, event args sınıfınızı winrt::deferrable_event_args sınıfından türetirsiniz. < deferrable_event_argsT>, sizin için T::GetDeferral'ı uygular. Ayrıca deferrable_event_args::wait_for_deferrals yeni bir yardımcı yöntemi de kullanıma sunar. Bu yöntem, tüm bekleyen ertelemeler tamamlandığında tamamlanır (erteleme alınmadıysa hemen tamamlanır).
// Widget.h
IAsyncOperation<bool> TryStartWidget(Widget const& widget)
{
auto args = make_self<WidgetStartingEventArgs>();
// Raise the event to let people know that the widget is starting
// and give them a chance to prevent it.
m_starting(widget, *args);
// Wait for deferrals to complete.
co_await args->wait_for_deferrals();
// Use the results.
bool started = false;
if (!args->Cancel())
{
widget.InsertBattery();
widget.FlipPowerSwitch();
started = true;
}
co_return started;
}
Tasarım yönergeleri
Fonksiyon parametreleri olarak temsilciler yerine olayları geçirmenizi öneririz. winrt::event öğesinin add işlevi tek istisnadır, çünkü bu durumda bir temsilci geçirmeniz gerekir. Bu yönergenin nedeni, temsilcilerin farklı Windows Çalışma Zamanı dillerinde farklı formlar alabilmesidir (bir istemci kaydını veya birden çokunu destekleyip desteklemedikleri açısından). Birden çok abone modeline sahip olaylar, çok daha öngörülebilir ve tutarlı bir seçenek oluşturur.
Olay işleyicisi temsilcisinin imzası iki parametreden oluşmalıdır: sender (IInspectable) ve args (bazı olay bağımsız değişken türü, örneğin RoutedEventArgs).
İç API tasarlarken bu yönergelerin geçerli olması gerekmediğini unutmayın. Ancak iç API'ler genellikle zaman içinde genel kullanıma sunulur.
İlgili konular
Windows developer