Monday, 1 October 2012

Displaying design-time data in a C++/CX app

Previously I’ve written about detecting design mode in Blend, specifically in a WinJS app. This is sometimes necessary if you want to enable the designer-developer workflow. The designer-developer workflow means that during the app development process, designers and developers can work independently and concurrently on their components. The designers can concentrate on the UI in Blend, displaying sample data to view layout sizes accurately and see realistic results for sizing and styling, while the developers can work on the code in Visual Studio.

In most circumstances for HTML5 apps, Blend can automatically get data from the file system without any additional effort from the developer, although it’s occasionally necessary to add logic to check for design mode. However, more work is required to display data from the file system at design-time in a C++/CX app.

In a previous blog post, I extended a sample photo viewing app to use the Repository pattern so that access to the underlying data source, in this case the file system, is through a centralized data access layer. In this blog post I will add design-time data to the app, in order to enable the designer-developer workflow.

The sample application can be downloaded here.

Implementation

To display data in the designer, you must declare it in XAML instead of just setting the DataContext property programmatically in code-behind. This is necessary because when you open a page or user control in the designer, it is not instantiated. The designer parses the XAML, but does not run its code-behind. However, the designer will instantiate any child user controls that it encounters when it parses the XAML content.

The technique adopted here for displaying design-time data is to use design-time attributes in page’s XAML. To do this, you must ensure that the designer namespace is declared in your XAML file.

xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
With this declaration, attributes with d: prefixes are interpreted only at design-time and are ignored at run time. Then, a DesignTimeData class is specified. Note that the class must have the Windows::UI::Xaml::Data::Bindable attribute set on it.
namespace PhotoViewer
{
    [Windows::UI::Xaml::Data::Bindable]
    public ref class DesignTimeData sealed
    {
    public:
        property Windows::UI::Xaml::Media::ImageSource^ Photo
        {
            Windows::UI::Xaml::Media::ImageSource^ get();
        }
    };
}
This class only contains one property, Photo, which will return an ImageSource object to the designer. The implementation file for this class is shown below. It simply returns a PNG file as a BitmapImage.
ImageSource^ DesignTimeData::Photo::get()
{
    return ref new BitmapImage(ref new Uri("ms-appx:///Assets/Logo.png"));
}
On the root Grid of the page you want to display design-time data on, in this case the PhotoView page, you then specify the design-time DataContext for the page.
<Grid x:Name="ContentRoot"
      d:DataContext="{Binding Source={d:DesignInstance Type=local:DesignTimeData, IsDesignTimeCreatable=True}}"
      Background="{StaticResource ApplicationPageBackgroundThemeBrush}"
The d:DesignInstance markup extension indicates that the design-time source is a designer-created instanced based on the DesignTimeData type. The IsDesignTimeCreatable setting indicates that the designer will instantiate that type directly, which is necessary to display the design-time data. If you don’t set this attribute (or you set it to False), the designer instead generates and instantiates a lightweight class with the same bindable properties. This is only useful if you just want the properties to appear as potential binding targets in the data binding designer, but you don’t care about displaying sample data. The Image control on the PhotoView page binds to the Photo property to display an image. At design-time the Photo property from the DesignTimeData class is bound to, while at run-time the Photo property from the PhotoViewModel class is bound to.
<Image HorizontalAlignment="Center"
       Source="{Binding Photo}"
       VerticalAlignment="Center" />
In order to build the app, you need to include the header file for the DesignTimeData class, DesignTimeData.h, in the App.xaml.h header file, either indirectly or directly. This ensures that the types necessary to work with XAML are generated at compile time. Then, when viewed in both the Visual Studio Designer or the Blend designer you will see an image on the PhotoView page, enabling designers to proceed with any layout/styling changes required.

blend

The image shown in the screenshot above is simply the default logo (Logo.png) for a Windows store app project.

For a more complicated implementation of design-time data, which includes grouped data, see the Hilo project.

Summary


Design-time data can be added to Windows Store apps written in C++/CX, in order to enable the designer-developer workflow. The designer-developer workflow means that during the app development process, designers and developers can work independently and concurrently on their components. The designers can concentrate on the UI in Blend, displaying sample data to view layout sizes accurately and see realistic results for sizing and styling, while the developers can work on the code in Visual Studio.

No comments:

Post a Comment