Blendability

To be able to effectively design your application's user interface, designers often like to know the shape of the data that they are binding to, enabling them to take full advantage of the Expression Blend or Visual Studio XAML designer without resorting to editing the XAML directly. This allows them to see what fields are available in the data, and bind to them as required.

It can also be beneficial to be able to populate a view with data at design time in order to picture how it will appear to the user, and customize its appearance accordingly, instead of having to constantly compile and run the application to do so.

These features make the process of designing user interfaces more interactive, and are known as blendability. As you may have guessed from the name, this concept primarily relates to user interface design in Expression Blend, but we can also harness these design time features in the Visual Studio XAML designer via the same underlying mechanism (although with less support than provided by Expression Blend).

The Design-Time Data Mechanisms

As you might recall from Chapter 2, the design-time data mechanisms can be found in the Expression Blend 2008 namespace (http://schemas.microsoft.com/expression/blend/2008), which is automatically declared in your XAML files with a prefix of d. In this namespace, you will find the following data-related attached properties:

  • DataContext
  • DesignData
  • DesignSource

You will also find the DesignData and DesignInstance markup extensions. We'll be using these to provide the blendability features in the XAML designer.

Defining the Shape of the Data

Let's start by defining the type of data that we will bind to, so that the data binding expression builder (discussed in Chapter 11) knows the structure of the data that you are binding to. In Chapter 5, you might have noticed that when you drag an entity returned from the server via RIA Services from the Data Sources window and drop it onto the design surface, the DomainDataSource control that's created for you has a design-time data property already applied:

<riaControls:DomainDataSource AutoLoad="True"
                      d:DesignData="{d:DesignInstance my1:ProductSummary,
                                    CreateList=true}"

                      Height="0" Width="0"
                      LoadedData="productSummaryDDS_LoadedData"
                      Name="productSummaryDDS"
                      QueryName="GetProductSummaryListQuery">
    <riaControls:DomainDataSource.DomainContext>
        <my:ProductsContext />
    </riaControls:DomainDataSource.DomainContext>
</riaControls:DomainDataSource>

The rather confusingly named d:DesignData design-time attached property—it has nothing to do with the d:DesignData markup extension, discussed shortly—is used to define the type of data that is served by a data source control via its Data property. Hence, this property can be applied only to data sources such as the DomainDataSource control. The key benefit of applying this design-time property to the DomainDataSource control is that you will now be able to see a list of available properties, from the type of data that it returns, and select a property to bind to when using the data binding expression builder (see Figure 11-3 in Chapter 11) on controls using it as a data source. For example, if the DomainDataSource control returns a collection of Product entities, you'll be able to bind a TextBox control's Text property to the Name property of a product by opening the data binding expression builder, and selecting the Name property from a list of the Product entity's fields.

To configure this property, we assign it a d:DesignInstance markup extension. This markup extension is primarily used to return an object of a given type or a collection of objects of that type. The default property on this markup extension is the Type property. You'll note from our example that it specifies that the DomainDataSource control will be returning ProductSummary entities. You will also note that the CreateList property of this markup extension is set to true. This is used to indicate whether the d:DesignInstance markup extension should return a collection of the given object type or a single instance of the object type.

By default, the d:DesignInstance markup extension reflects over the given object type, and creates and returns a corresponding substitute design-time type or an empty collection of that type if the CreateList property is set to true, which the XAML designer can use where required. However, it also has an IsDesignTimeCreatable property, which, when set to true, will actually instantiate and return an object of the given type, which is only of use when the CreateList property is set to false. Once you assign values to that object's properties in its constructor, these values will appear in the XAML designer—essentially populating it with data at design time.

You can also assign the d:DesignInstance markup extension to the d:DataContext design-time attached property. Whereas the d:DesignData property could be applied only to data source controls, the d:DataContext property is designed to be applied to controls that will bind to data via their DataContext property. Like data assigned to the DataContext property of a control, the value assigned to the d:DesignContext property will be inherited down the object hierarchy. For example, setting the d:DataContext property on a Grid, as demonstrated by the TextBlock control in the following example, will enable the data binding expression builder to display the available properties that the controls within the Grid can be bound to.

Grid d:DataContext="{d:DesignInstance Type=my1:ProductSummary}">
    <TextBlock Text="{Binding Path=Name}" />
</Grid>

Using Sample Data

We've made the designer much friendlier for creating bindings, so let's now look at populating it with some sample data at design time. One way of doing this is to populate a single instance of an object with data in its constructor, and set the IsDesignTimeCreatable property on the d:DesignInstance markup extension to true. However, this is hardly an ideal solution for implementing design-time data. The design-time data has to be hard-coded in the class (not a good idea), and this method is suitable only when binding to a single object rather than to a collection of objects. There is another option however, and that's using the d:DesignData markup extension in place of the d:DesignInstance markup extension.

The d:DesignData markup extension has only a single property, named Source, which is, therefore, its default property. The design-time data needs to be defined in a separate XAML file, and you simply point the Source property to a XAML file containing the design-time data. That data will then be displayed in the XAML designer.

d:DataContext="{d:DesignData Source=/SampleData/ProductSampleData.xaml}"

The easiest way to create a sample data XAML file and populate it with data is from within Expression Blend. Expression Blend gives you the options of importing some data from XML, creating random data conforming to the structure of a given class, or simply creating your own structure before populating it with random data. Explaining how to create sample data files in Expression Blend is beyond the scope of this book, but you can find more information on doing so in the Expression Blend help, or on creating them manually in Visual Studio at this MSDN page: http://msdn.microsoft.com/en-us/library/ff602279.aspx.

Sample data XAML files should have a Build Action of either DesignData, where a substitute design-time type will be generated and used in place of the objects that the sample data is populating, or DesignDataWithDesignTimeCreatableTypes, where the actual objects the sample data is populating are instantiated and used at design time. You can then use the d:DesignData markup extension to point to the sample data XAML file and assign it to the d:DataContext attached property, as required.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.218.137.93