I am working on a simple C++/WinRT UWP application to learn about how to link XAML events and the C++/WinRT source code for the actual handlers for these events.
I have a XAML source for a simple grid that contains a blue rectangle. Beside the blue rectangle is a button to click from earlier work to trigger a handler when the button is clicked. That worked fine.
Now I want to handle mouse pointer events. However the C++/WinRT source code build is generating a link error. I assume this means that the handler in the source code does not have the correct interface.
However I have been unable to divine thus far the correct signature and I am running out of goats for the necessary entrails.
Can someone tell me what the event handler for a pointer event should be?
I would like to have the necessary interface for the following pointer events that I am currently exploring:
- PointerExited
- PointerReleased
- PointerPressed
The MainPage.h file contains the following declarations:
namespace winrt::BlankAppTouch1::implementation
{
struct MainPage : MainPageT<MainPage>
{
MainPage();
int32_t MyProperty();
void MyProperty(int32_t value);
void ClickHandler(Windows::Foundation::IInspectable const & sender, Windows::UI::Xaml::RoutedEventArgs const& args);
// Handler for pointer exited event.
void PointerExitedHandler(Windows::Foundation::IInspectable const & sender, Windows::UI::Xaml::RoutedEventArgs const& token);
// Handler for pointer released event.
void touchRectangle_PointerReleased(Windows::Foundation::IInspectable const & sender, Windows::UI::Xaml::RoutedEventArgs const& e);
// Handler for pointer pressed event.
void touchRectangle_PointerPressed(Windows::Foundation::IInspectable const & sender, Windows::UI::Xaml::RoutedEventArgs const& e);
};
}
and the MainPage.cpp file contains the following source:
#include "pch.h"
#include "MainPage.h"
using namespace winrt;
using namespace Windows::UI::Xaml;
using namespace Windows::UI::Xaml::Input;
using namespace Windows::UI::Xaml::Shapes;
namespace winrt::BlankAppTouch1::implementation
{
MainPage::MainPage()
{
InitializeComponent();
}
int32_t MainPage::MyProperty()
{
throw hresult_not_implemented();
}
void MainPage::MyProperty(int32_t /* value */)
{
throw hresult_not_implemented();
}
void MainPage::ClickHandler(Windows::Foundation::IInspectable const&, Windows::UI::Xaml::RoutedEventArgs const&)
{
myButton().Content(box_value(L"Clicked"));
}
// Handler for pointer exited event.
void MainPage::PointerExitedHandler(Windows::Foundation::IInspectable const & sender, Windows::UI::Xaml::RoutedEventArgs const& token)
{
Rectangle rect = winrt::unbox_value<Rectangle>(sender);
// Pointer moved outside Rectangle hit test area.
// Reset the dimensions of the Rectangle.
if (nullptr != rect)
{
rect.Width(200);
rect.Height(100);
}
}
// Handler for pointer released event.
void MainPage::touchRectangle_PointerReleased(Windows::Foundation::IInspectable const & sender, Windows::UI::Xaml::RoutedEventArgs const& e)
{
Rectangle rect = winrt::unbox_value<Rectangle>(sender);
// Reset the dimensions of the Rectangle.
if (nullptr != rect)
{
rect.Width(200);
rect.Height(100);
}
}
// Handler for pointer pressed event.
void MainPage::touchRectangle_PointerPressed(Windows::Foundation::IInspectable const & sender, Windows::UI::Xaml::RoutedEventArgs const& e)
{
Rectangle rect = winrt::unbox_value<Rectangle>(sender);
// Change the dimensions of the Rectangle.
if (nullptr != rect)
{
rect.Width(250);
rect.Height(150);
}
}
}
And the MainPage.xaml file contains the following source:
<Page
x:Class="BlankAppTouch1.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:BlankAppTouch1"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center">
<Rectangle x:Name="touchRectangle"
Width="200" Height="200" Fill="Blue"
PointerExited="PointerExitedHandler"
ManipulationMode="All"/>
<Button x:Name="myButton" Click="ClickHandler">Click Me</Button>
</StackPanel>
</Grid>
</Page>
The link error is fatal error LNK1120: 1 unresolved externals with the following description:
unresolved external symbol "public: __thiscall winrt::Windows::UI::Xaml::Input::PointerEventHandler::PointerEventHandler(struct winrt::BlankAppTouch1::implementation::MainPage ,void (__thiscall winrt::BlankAppTouch1::implementation::MainPage::)(struct winrt::Windows::Foundation::IInspectable const &,struct winrt::Windows::UI::Xaml::RoutedEventArgs const &))" (??$?0UMainPage@implementation@BlankAppTouch1@winrt@@P80123@AEXABUIInspectable@Foundation@Windows@3@ABURoutedEventArgs@Xaml@UI@63@@Z@PointerEventHandler@Input@Xaml@UI@Windows@winrt@@QAE@PAUMainPage@implementation@BlankAppTouch1@5@P86785@AEXABUIInspectable@Foundation@45@ABURoutedEventArgs@2345@@Z@Z) referenced in function "public: void __thiscall winrt::BlankAppTouch1::implementation::MainPageT::Connect(int,struct winrt::Windows::Foundation::IInspectable const &)" (?Connect@?$MainPageT@UMainPage@implementation@BlankAppTouch1@winrt@@$$V@implementation@BlankAppTouch1@winrt@@QAEXHABUIInspectable@Foundation@Windows@4@@Z)
If I remove the PointerExited="PointerExitedHandler" clause from the XAML describing the Rectangle, it compiles fine and when run displays what is expected as in the following screenshot.
Addendum A: Changes and errors
After removing the clause from the XAML I then tried to put the handler for the pointer exit handler into the rectangle object itself. Recompiling, I get what appears to be the same unresolved external symbol link error.
MainPage::MainPage()
{
InitializeComponent();
touchRectangle().PointerExited({ this, &MainPage::PointerExitedHandler });
}
If I modify the name of the handler specified in the PointerExited() method by adding the letter x to the name of the handler function (as in touchRectangle().PointerExited({ this, &MainPage::PointerExitedHandlerx });), I see compiler errors indicating the identifier PointerExitedHandlerx does not exist, as expected.
Severity Code Description Project File Line Suppression State
Error C2039 'PointerExitedHandlerx': is not a member of 'winrt::BlankAppTouch1::implementation::MainPage' BlankAppTouch1 d:\users\rickc\documents\vs2017repos\blankapptouch1\blankapptouch1\mainpage.cpp 15
Error C2065 'PointerExitedHandlerx': undeclared identifier BlankAppTouch1 d:\users\rickc\documents\vs2017repos\blankapptouch1\blankapptouch1\mainpage.cpp 15
Addendum B: PointerEventHandler struct
The definition for a PointerEventHandler from Windows.UI.Input.2.h is:
struct PointerEventHandler : Windows::Foundation::IUnknown
{
PointerEventHandler(std::nullptr_t = nullptr) noexcept {}
template <typename L> PointerEventHandler(L lambda);
template <typename F> PointerEventHandler(F* function);
template <typename O, typename M> PointerEventHandler(O* object, M method);
void operator()(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::Input::PointerRoutedEventArgs const& e) const;
};
and PointerRoutedEventArgs is defined as:
#define WINRT_EBO __declspec(empty_bases)
// other source for definitions, etc.
struct WINRT_EBO PointerRoutedEventArgs :
Windows::UI::Xaml::Input::IPointerRoutedEventArgs,
impl::base<PointerRoutedEventArgs, Windows::UI::Xaml::RoutedEventArgs>,
impl::require<PointerRoutedEventArgs, Windows::UI::Xaml::IRoutedEventArgs, Windows::UI::Xaml::Input::IPointerRoutedEventArgs2>
{
PointerRoutedEventArgs(std::nullptr_t) noexcept {}
};
Documentation links
