Thursday, 29 November 2012

Creating an attached behaviour in a C++/CX app

Previously I’ve developed a sample photo viewing app to show how to implement a Windows Store app in C++/CX. The app uses MVVM as an architectural pattern in order to separate concerns between the user interface controls and their logic.

In MVVM, ideally the views should be defined purely in XAML, with a limited code-behind that does not contain business logic. However, in the sample app there is an event handler in the code behind for the MainView. The XAML file for the MainView class contains a GridView that is used to display photo thumbnails, and which registers an event handler for the ItemClick event.

<GridView Grid.Row="1"
          IsItemClickEnabled="True"
          ItemClick="OnPhotoClick"
          ItemsSource="{Binding Photos}"
          Margin="140,0,0,0"
          SelectionMode="Single">

When a GridViewItem (which represents a photo thumbnail) is clicked upon the ItemClick event of the GridView fires, which runs the OnPhotoClick event handler in the MainView code-behind. This event handler is used to navigate the app to the Photo page, which displays the full photo rather than just it’s thumbnail.

void MainView::OnPhotoClick(Object^ sender, ItemClickEventArgs^ e)
{
    auto photo = dynamic_cast<Windows::Storage::BulkAccess::FileInformation^>(e->ClickedItem);
    if (nullptr != photo)
    {
        PhotoNavigationData photoData(photo);
        PhotoViewerPage::NavigateToPage(PageType::Photo, photoData.SerializeToString());
    }
}

This approach presents a number of disadvantages:

  1. There’s event handler code in the code-behind file. For MVVM purists this is unacceptable as it doesn’t promote a clean separation of concerns.
  2. Navigation is being invoked from a view. Ideally, navigation should be invoked from a view model, from where it can be easily tested.

These disadvantages can be addressed by implementing an attached behaviour that executes a view model command in response to the ItemClick event of the GridView being raised.

Implementation

This implementation defines a behaviour called ListViewItemClickBehaviour. This behaviour executes a view model command in response to the ItemClick event firing on the GridView. The first step in the implementation is to define a custom attached property for the behaviour. The syntax of a custom attached property can be viewed at Custom attached properties.

An attached property is a specialized form of a dependency property. Attaching a behaviour to an object simply means making the object do something that it would not normally do. The idea is that you set an attached property on an element so that you can gain access to the element from the class that exposes the attached property. Once that class has access to the element it can hook onto events on it, and in response to those events firing make the element do things that it would normally not do.

There are several options for how to split the implementation between the header and the code file. The usual split is to declare the DependencyProperty as a public static property in the header, with a get implementation but no set. The get implementation refers to a private field, which is an uninitialized DependencyProperty instance. You should also declare the wrappers in the header file.

static property Windows::UI::Xaml::DependencyProperty^ CommandProperty
{
    Windows::UI::Xaml::DependencyProperty^ get();
}
static DelegateCommand^ GetCommand(Windows::UI::Xaml::DependencyObject^ element);
static void SetCommand(Windows::UI::Xaml::DependencyObject^ element, DelegateCommand^ value);

The DependencyProperty should be initialized in the code file outside of any function definition, via a call to the RegisterAttached method. The return value of the RegisterAttached method is used to fill the static but uninitialized identifier that is declared in the header file. In C++ the property is registered the first time the owner class is used. The reason why there’s a private backing field plus a public read-only property that surfaces the DependencyProperty is so that the other callers who use your dependency property can also use property-system utility APIs that require the identifier. If you keep the identifier private, people can’t use these utility APIs. For more information see Custom dependency properties.

DependencyProperty^ ListViewItemClickBehaviour::_commandProperty =
    DependencyProperty::RegisterAttached("Command",
    DelegateCommand::typeid, ListViewItemClickBehaviour::typeid,
    ref new PropertyMetadata(nullptr, ref new PropertyChangedCallback(&ListViewItemClickBehaviour::OnCommandPropertyChanged)));
 
DependencyProperty^ ListViewItemClickBehaviour::CommandProperty::get() 
{
    return _commandProperty;
}
 
DelegateCommand^ ListViewItemClickBehaviour::GetCommand(DependencyObject^ element)
{
    return safe_cast<DelegateCommand^>(element->GetValue(ListViewItemClickBehaviour::CommandProperty));
}
 
void ListViewItemClickBehaviour::SetCommand(Windows::UI::Xaml::DependencyObject^ element, DelegateCommand^ value)
{
    element->SetValue(ListViewItemClickBehaviour::CommandProperty, value);
}

Note that property metadata is assigned to the DependencyProperty. Two behaviours are specified – a default value that the property system assigns to all cases of the property, and a static callback method that is automatically invoked within the property system whenever a property value is detected. Therefore, the idea is that when the value of the Command DependencyProperty changes, the OnCommandPropertyChanged callback specified in the DependencyProperty will be invoked.

void ListViewItemClickBehaviour::OnCommandPropertyChanged(DependencyObject^ sender, DependencyPropertyChangedEventArgs^ e) 
{
    ListViewBase^ listView = safe_cast<ListViewBase^>(sender);
    if (listView != nullptr)
    {
        _itemClickEventToken = listView->ItemClick::add(ref new ItemClickEventHandler(&ListViewItemClickBehaviour::OnListViewItemClicked));
        _unloadedEventToken = listView->Unloaded::add(ref new RoutedEventHandler(&ListViewItemClickBehaviour::OnListViewUnloaded));
    }
}
 
void ListViewItemClickBehaviour::OnListViewItemClicked(Object^ sender, ItemClickEventArgs^ e)
{
    ListViewBase^ listView = safe_cast<ListViewBase^>(sender);
 
    auto command = GetCommand(listView);
    if (command != nullptr)
    {
        command->Execute(e->ClickedItem);
    }
}
 
void ListViewItemClickBehaviour::OnListViewUnloaded(Object^ sender, RoutedEventArgs^ e)
{
    ListViewBase^ listView = safe_cast<ListViewBase^>(sender);
    listView->ItemClick::remove(_itemClickEventToken);
    listView->Unloaded::remove(_unloadedEventToken);
}

The OnCommandPropertyChanged method gets the instance of ListViewBase and registers event handlers for the ItemClick and Unloaded events. The ListViewBase class is the base class for both the GridView and the ListView. The OnListViewItemClicked method handles the ItemClick event for the ListViewBase instance and gets the command associated with the instance and executes it. The OnListViewUnloaded method handles the Unloaded event and simply deregisters the event handlers when the control is unloaded (such as when page navigation occurs).

In the MainViewModel class, the constructor creates a DelegateCommand instance for the NavigateCommand property that will execute the NavigateToPhotoPage method when the command is executed.

MainViewModel::MainViewModel(shared_ptr<Repository> repository) : m_repository(repository)
{
     m_navigateCommand = ref new DelegateCommand(ref new ExecuteDelegate(this, &MainViewModel::NavigateToPhotoPage), nullptr);
}
 
ICommand^ MainViewModel::NavigateCommand::get()
{
    return m_navigateCommand;
}
 
void MainViewModel::NavigateToPhotoPage(Object^ parameter)
{
    auto photo = dynamic_cast<Windows::Storage::BulkAccess::FileInformation^>(parameter);
    if (nullptr != photo)
    {
        PhotoNavigationData photoData(photo);
        GoToPage(PageType::Photo, photoData.SerializeToString());
    }
}

The NavigateToPhotoPage method replicates the code that previously was present in the OnPhotoClick event handler in the MainView page. It uses the GoToPage method contained in the base ViewModel class.

Finally, the behaviour must be attached to the GridView in the MainView class. To do this the attach property syntax is used.

<GridView local:ListViewItemClickBehaviour.Command="{Binding NavigateCommand}"
          Grid.Row="1"
          IsItemClickEnabled="True"
          ItemsSource="{Binding Photos}"
          Margin="140,0,0,0"
          SelectionMode="Single">

Now the GridView does not specify an event handler for the ItemClick method, instead specifying a command that will be executed for the attached behaviour. When the value of the ListViewItemClickBehaviour::Command DependencyProperty is initialized to the NavigateCommand in the MainViewModel class, the ListViewItemClickBehaviour::OnCommandPropertyChanged event handler executes, which registers event handlers for the ItemClick and Unloaded events of the GridView. So when the user clicks on a photo thumbnail, the ItemClick event of the GridView fires, which executes the ListViewItemClickBehaviour::OnListViewItemClicked event handler, which executes the NavigateCommand in the MainViewModel class. The NavigateCommand executes the MainViewModel::NavigateToPhotoPage method, which executes the ViewModel::GoToPage method, causing page navigation to occur. Just before page navigation occurs, the Unloaded event on the GridView fires, causing the ListViewItemClickBehaviour:: OnListViewUnloaded event handler to run, which de-registers the ItemClick and Unloaded event handlers in order to prevent memory leaks.

Summary

The attached behaviour implemented here allows a view model command to be executed when an event fires on a GridView control. This approach eliminates the event handler that was present in the MainViewModel class, and ensures that navigation is only invoked from view model classes, where it can be easily tested. A behaviour could be implemented for other common events such as Tapped, by working on a UIElement or a Control. Such a behaviour would then work for all derived controls.

The sample app can be downloaded here.

Thursday, 22 November 2012

Unit testing a C++/CX app

There are many ways that a Windows Store app should be tested, including:

  • Unit testing
  • Integration testing
  • UX testing
  • Security testing
  • Localization testing
  • Accessibility testing
  • Performance testing
  • Device testing

Hilo was designed for testability and so all of these approaches were used. However, unit testing C++/CX code presented it’s own problems – specifically how to test asynchronous code, and code that must run on the UI thread.

In this blog post I’ll extend the sample photo viewing app I’ve previously developed to include unit tests. In Visual Studio, you can create a unit test project for apps written in C++/CX by using the Native Test Project template.

Implementation

The PhotoViewerTests project contains helper classes, a mock repository class, links to the classes under test, and the unit tests themselves. The unit tests can be ran by selecting Test > Run > All Tests in Visual Studio.MK

A simple unit test is shown below, from the PhotoViewModelTests class. It tests that the PhotoViewModel constructor initializes the GreyscaleCommand property. The unit test demonstrates testing code that must run on the UI thread.

TEST_METHOD(PhotoViewModelShouldSetupGreyscaleCommandWhenConstructed)
{
    auto vm = make_shared<PhotoViewModel^>(nullptr);
    TestHelper::RunUISynced([this, vm]()
    {
        (*vm) = ref new PhotoViewModel(m_repository);
    });
    Assert::IsNotNull((*vm)->GreyscaleCommand);
}

This unit test creates a shared pointer instance of the PhotoViewModel class, and then initializes the shared pointer instance to a new instance of the PhotoViewModel class, as a lambda embedded in the call to the RunUISynced method. RunUISynced is a helper method provided in the project that enables code that must be executed on the UI thread to be tested through unit tests. Notice that the PhotoViewModel constructor accepts a shared pointer of type Repository. The PhotoViewerTests project provides a class named StubRepository which implements the Repository type. The m_repository member variable is initialized to a shared pointer instance of the StubRepository class in the Initialize method of the PhotoViewModelTests class. The unit test then asserts that the GreyscaleCommand property of the PhotoViewModel class has been initialized to a value, and hence is not null.

A more complicated unit test is shown below, from the ThumbnailConverterTests class. It tests that the Convert method of the ThumbnailConverter class can convert a thumbnail to a BitmapImage. The unit test demonstrates testing code that must run on the UI thread, and code that’s asynchronous.

TEST_METHOD(ThumbnailConverterCanConvertThumbnailToBitmapImage)
{
    TestImageGenerator imageGenerator;
    Object^ bitmap = nullptr;
 
    TestHelper::RunUISynced([this, &bitmap, &imageGenerator]()
    {
        task_status status;
        auto fi = make_shared<FileInformation^>(nullptr);
        auto createTestImageTask = imageGenerator.CreateTestImageFileFromLocalFolder("UnitTestLogo.png", "TestFile.png")
            .then([fi](FileInformation^ file)
        {
            (*fi) = file;
            return file->GetThumbnailAsync(ThumbnailMode::PicturesView);
        });
 
        auto stream = TestHelper::RunSynced(createTestImageTask, status);
        auto thumbnailConverter = ref new ThumbnailConverter();
        TypeName bitmapImageTypeName = { "BitmapImage", TypeKind::Metadata };
        bitmap = thumbnailConverter->Convert(stream, bitmapImageTypeName, nullptr, "en-GB");
    });
 
    Assert::IsNotNull(bitmap);
 
    TestHelper::RunUISynced([&imageGenerator]()
    {
        task_status status;
        TestHelper::RunSynced(imageGenerator.DeleteFilesAsync(), status);
    });
}

As a lambda embedded in the call to the RunUISynced method, this unit test creates a shared pointer instance of a FileInformation object, and then creates a task that will call the CreateTestImageFileFromLocalFolder method to create a new file named TestFile.png from the UnitTestLogo.png file that’s one of the projects resources. The CreateTestImageFileFromLocalFolder method is a helper method in the TestImageGenerator class. Once the file is created, GetThumbnailAsync is called in order to retrieve the thumbnail for the file. The task is then executed through the call to the RunSynced method. RunSynced is a helper method that enables asynchronous operations to be tested through unit tests. An instance of the ThumbnailConverter class is then created, and then the Convert method is called on the instance in order to convert the retrieved thumbnail to a BitmapImage.The unit test then asserts that the bitmap local variable is not null. Finally, a lambda embedded in the call to the RunUISynced method calls the DeleteFilesAsync method to delete the previously created TestFile.png file. The DeleteFilesAsync method is a helper method in the TestImageGenerator class.

Please note that while the PhotoViewerTests project contains other unit tests, they are illustrative rather than exhaustive. For more information about writing unit tests in C++, see Writing Unit tests for C/C+ with the Microsoft Unit Testing Framework for C++.

Summary


In this blog post I’ve extended the sample photo viewing app to include a unit test project. The unit test project tests business logic in the app, and contains helper methods that enable you to unit test both asynchronous code, and code that must execute on the UI thread.

The sample app, including the unit test project, can be downloaded here. To download the unit and integration test project for Hilo, see Hilo’s codeplex site.

Monday, 12 November 2012

Thread context in C++/CX apps

When developing Hilo we discovered that there are special context rules for task continuations that wrap async objects, or that use the create_async function. Therefore, in order to clarify our understanding of the thread context for our subroutines we developed three helper functions -  IsMainThread, IsBackgroundThread, and RecordMainThread. These functions allow clarification of whether a task continuation is running on the UI thread (main thread), or a thread pool thread (background thread).

The sample photo viewing app has been extended to include these helper functions, which are invoked in an assertion. In the Debug version of the sample app, these statements throw an exception if the thread being used is other than the one declared in the assertion.

Implementation

The IsMainThread, IsBackgroundThread, and RecordMainThread functions are shown below. The RecordMainThread function calls GetCurrentThreadId and stores the result in the mainThreadID variable. Then the IsMainThread function can be used to compare the value of the mainThreadId variable to the value returned by GetCurrentThreadId, and if they are identical, the function returns true. Similarly, the IsBackgroundThread function can be used to compare the value of the mainThreadId variable to the value returned by GetCurrentThreadId, and if they are not identical, the function returns true.

bool IsMainThread()
{
    return (mainThreadId == 0U || mainThreadId == GetCurrentThreadId());
}
 
bool IsBackgroundThread()
{
    return (mainThreadId == 0U || mainThreadId != GetCurrentThreadId());
}
 
void RecordMainThread()
{
    mainThreadId = GetCurrentThreadId();
}

The RecordMainThread function is invoked in the constructor of the App class, the entry point of the app. Note that the RecordMainThread function is only invoked if the build of the app is a Debug build.

App::App()
{
#ifndef NDEBUG
    RecordMainThread();
#endif
    InitializeComponent();
    Suspending += ref new SuspendingEventHandler(this, &App::OnSuspending);
}

The IsMainThread and IsBackgroundThread functions can then be wrapped in assertions which can be used to clarify your understanding of the thread context that your task continuations are running on.

ImageSource^ PhotoViewModel::Photo::get()
{
    if (nullptr == m_photo)
    {
        auto photoStream = make_shared<IRandomAccessStreamWithContentType^>(nullptr);
        auto backgroundContext = task_continuation_context::use_arbitrary();
 
        GetPhotoAsync().then([this](FileInformation^ file)
        {
            assert(IsBackgroundThread());
            if (file == nullptr)
            {
                cancel_current_task();
            }
            m_file = file;
            return file->OpenReadAsync();
        }, backgroundContext).then([photoStream](IRandomAccessStreamWithContentType^ imageData)
        {
            assert(IsBackgroundThread());
            (*photoStream) = imageData;
            return BitmapDecoder::CreateAsync(imageData);
        }, backgroundContext).then([this, photoStream](BitmapDecoder^ decoder)
        {
            assert(IsMainThread());
            m_photo = ref new WriteableBitmap(decoder->PixelWidth, decoder->PixelHeight);
            (*photoStream)->Seek(0);
            return m_photo->SetSourceAsync(*photoStream);
        }).then([this]()
        {
            assert(IsMainThread());
            if (m_isGreyscale)
            {
                ConvertPhotoToGreyscale(nullptr);
            }
            OnPropertyChanged("Photo");
        });
    }
    return m_photo;
}

In the getter of the Photo property in the PhotoViewModel class, the code asserts that the first continuation is running on a thread pool thread, rather than the UI thread. This is as expected as the continuation is declared to use an arbitrary thread from the thread pool. The second continuation also asserts that the continuation is running on on a thread pool thread, which is also as expected as the continuation is declared to use an arbitrary thread from the thread pool. The final two continuations assert that the continuations are running on the UI thread, which is also as expected because the continuations do not specify a thread to run on. The first two continuations run on thread pool threads in order to keep the UI responsive. The code then switches to running on the UI thread for the final two continuations because they both need to run on the UI thread as they update data on the UI.

Summary


In this blog post I’ve extended the sample photo viewing app to include functions that can be invoked in assertions to clarify the thread a task continuation is executing on. In the Debug version of the sample app, these statements throw an exception if the thread being used is other than the one declared in the assertion. This approach to clarifying thread context rules was discussed in a presentation at //build/ about Hilo, which can be viewed here.

The sample app can be downloaded here.