C++ and Metro: event handling and MessageBox

This entry is part of a series, C++ Metro applications»

In the previous post we have created simple Metro application using C++ as the language of choice. Now we are going to add some interactivity into it.

MessageDialog

Add a simple button and using the following XAML snippet:

<Button Content="Click me" Click="Button_Click_1" Margin="12,20" />

Right click on the Button_Click_1 attribute value and select the Navigate to Event Handler. You will be transferred to the cpp file and both header and source file will be properly updated. Add the following code inside:

using namespace Windows::UI::Popups;
auto msgDlg = ref new MessageDialog("We want to notify you that you have successfully handled this event", "Vexing information");
msgDlg->ShowAsync();

If you run the code now, you will get the screen looking something like this:

Click the button and you the message box will be shown.

The MessageDialog class is similar to MessageBox class, but with a minor details. The first thing that You will notice is that the Show method ends with the Async suffix. Usually when you show a MessageBox dialog, the function is suspended until you click the OK button. However, all code after the ShowAsync method call will invoke immediately. To demonstrate this, add the following code immediately after the above snippet:

auto btn = dynamic_cast<Button^>(sender);
if (btn != nullptr)
	btn->Content = "Don't click me";

Compile and run the application and click on the button. You can notice that the button’s caption has been changed.

Notice how we used dynamic_cast for casting even though these are all COM objects. This is the power of C++/CX extensions which greatly simplify dealing with the otherwise cumbersome code.

The design philosophy for Metro applications is that all applications must stay responsive. Both the framework and the libraries support asynchronous constructs which simplify dealing with the asynchronous coding.

If you want to act after the user has closed the MessageDialog, you can do that easily via tasks. First include the header <ppltasks.h> and use the following code for adding the continuation task after the message dialog is closed:

using namespace Concurrency;
task<IUICommand^>(msgDlg->ShowAsync())
	.then([this](IUICommand^ command)
	{
		// check command or do some work
	});

Since you cannot capture local variables if they are handle or tracking reference, if you want to change the content for the button inside the lambda, do the following:

  1. Add the following attribute to the button in XAML: x:Name="btnClick"
  2. .

  3. Add this to the lambda’s captures.
  4. Inside the lambda’s body, write the following line
    btnClick->Content = "Click me";
    

Custom commands

If you want to add your own buttons and then add the handlers for them, you can do it via the Commands property of the MessageDialog instance. Add a new button in the XAML:

<Button Content="Enter the matrix" Click="Button_Matrix_Click" Margin="12,20" x:Name="btnMatrix" />

Write the following code for the click handler:

// in the BlankPage.xaml.h add the following line
void IgnoreButtonCallback(Windows::UI::Popups::IUICommand^ command);

// this goes into the BlankPage.xaml.cpp
void SimpleNativeApp::BlankPage::Button_Matrix_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
{
	using namespace Windows::UI::Popups;
	auto msgDlg = ref new MessageDialog("What will it be, Neo?", "Plot defining moment");

	msgDlg->Commands->Append(ref new UICommand("Red pill", ref new UICommandInvokedHandler([this](IUICommand^)
	{
		btnMatrix->Background = ref new Windows::UI::Xaml::Media::SolidColorBrush(Windows::UI::Colors::Red);
	})));
	msgDlg->Commands->Append(ref new UICommand("Blue pill", ref new UICommandInvokedHandler([this](IUICommand^)
	{
		btnMatrix->Background = ref new Windows::UI::Xaml::Media::SolidColorBrush(Windows::UI::Colors::Blue);
	})));
	msgDlg->Commands->Append(ref new UICommand("Ignore...", ref new UICommandInvokedHandler(this, &BlankPage::IgnoreButtonCallback)));

	using namespace Concurrency;
	msgDlg->ShowAsync();
}

void BlankPage::IgnoreButtonCallback(Windows::UI::Popups::IUICommand^ command)
{
	btnMatrix->Background = ref new Windows::UI::Xaml::Media::SolidColorBrush(Windows::UI::Colors::Gray);
}

Notice the UICommandInvokedHandler class used for handling events. In the first two instances we have used lambdas as the event handlers, but for the third instance we have bound local class method. You can either use unnamed lambdas or named functions as the event handlers.

Run the application and choose the different commands in the dialog. One possible scenario is visible on the image below.

That is all for today, we have seen how to cast reference counted objects, how to handle asynchronous tasks, how to construct event handlers. In the next post I will show how to use the idiomatic MVVM architecture in C++/XAML applications.

You can download the full source code for this sample from the following link: link.

Last updated by at .

Entries in this series:
  1. C++ and Metro: basic application
  2. C++ and Metro: event handling and MessageBox
Powered by Hackadelic Sliding Notes 1.6.5
  • http://www.facebook.com/yahya.alshaar.9 Yahya Alshaar

    Thank you very much