Telerik UI for Windows Phone by Progress

RadDataForm can be easily setup in XAML. The following article describes how you can define the Editor Fields, adjust their properties and fine-tune the DataForm's layout in XAML.

Defining Editor Fields in XAML

RadDataForm can be entirely set up in XAML by defining a main Grid element inline the RadDataForm element and putting the editors inside by using the FormField element. The following code snippet demonstrates the scenario from the Getting Started section implemented in XAML:

CopyXAML
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
    <telerikInput:RadDataForm
        EditorCreationMode="CreateByDefault"
        x:Name="radDataForm">
        <Grid>
            <telerikInput:DataField TargetProperty="FirstName"/>
            <telerikInput:DataField TargetProperty="SecondName"/>
            <telerikInput:DataField telerikDataForm:PasswordField.IsPasswordField="True" TargetProperty="Password"/>
            <telerikInput:DataField TargetProperty="ReceivesNewsLetter"/>
            <telerikInput:DataField TargetProperty="DateOfBirth"/>
            <telerikInput:DataField TargetProperty="Gender"/>
        </Grid>
    </telerikInput:RadDataForm>
</Grid>

Defining Groups of Editors

RadDataForm allows you to group several field editors on a panel with custom layout. This enables you to build complex form scenarios which are more readable and intuitive. This is done by using DataFieldGroup elements and putting the corresponding DataField elements inline:

CopyXAML
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
    <telerikInput:RadDataForm
        EditorCreationMode="CreateByDefault"
        x:Name="radDataForm">
        <Grid>
            <telerikInput:DataFieldGroup IsExpanded="True" AnimatedIndicatorContentTemplate="{x:Null}" Content="{x:Null}">
                <Grid>
                    <telerikInput:DataField TargetProperty="FirstName" Grid.Column="0"/>
                    <telerikInput:DataField TargetProperty="SecondName" Grid.Column="1" Grid.Row="0"/>
                </Grid>
            </telerikInput:DataFieldGroup>
            <telerikInput:DataField telerikDataForm:PasswordField.IsPasswordField="True" TargetProperty="Password"/>
            <telerikInput:DataField TargetProperty="ReceivesNewsLetter"/>
            <telerikInput:DataField TargetProperty="DateOfBirth"/>
            <telerikInput:DataField TargetProperty="Gender"/>
        </Grid>
    </telerikInput:RadDataForm>
</Grid>

The following screenshot shows the result of adding the code snippets from above:

Data Form Editor Group

Note
You do not need to explicitly define the Rows and the Columns in the main Grid panel as they are automatically generated.

Defining Expandable Groups of Editors

Once defined, an Editor Group can be expandable. And expandable group can be expanded or collapsed to show or hide the Editors accomodated by it. It also displays a Header and Expand/Collapse indicator to hint the user that there is an additional portion of editors which can be shown. Since by default the DataFieldGroup is expandable, you just need to leave its AnimatedIndicatorContentTemplate and additionally define Content which will be shown as a header for the group. When the user taps on the Content or AnimatedIndicatorContent portion, the expanded state of the group will be toggled. The following XAML snippet demonstrates how an expandable group is defined:

CopyXAML
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
    <telerikInput:RadDataForm
        EditorCreationMode="CreateByDefault"
        x:Name="radDataForm">
        <Grid>
            <telerikInput:DataFieldGroup Content="Names">
                <Grid>
                    <telerikInput:DataField TargetProperty="FirstName" Grid.Column="0"/>
                    <telerikInput:DataField TargetProperty="SecondName" Grid.Column="1" Grid.Row="0"/>
                </Grid>
            </telerikInput:DataFieldGroup>
            <telerikInput:DataField telerikDataForm:PasswordField.IsPasswordField="True" TargetProperty="Password"/>
            <telerikInput:DataField TargetProperty="ReceivesNewsLetter"/>
            <telerikInput:DataField TargetProperty="DateOfBirth"/>
            <telerikInput:DataField TargetProperty="Gender"/>
        </Grid>
    </telerikInput:RadDataForm>
</Grid>

Here is how the control would look like in this case:

Data Form Expandable Groups 1
Data Form Expandable Groups 2

Note
The IsExpandable property exposed by DataFieldGroup can be used to set the initial expanded state of the group.

Note
To make a DataFieldGroup expanded without the possibility to collapse it, simply set the IsExpanded property to true and set the AnimatedIndicatorContentTemplate and the Content properties to null to make sure that there are no elements in the header portion of the group that can accept user input to toggle its state.

Putting DataField elements in the Visible Editors portion of a group

For maximum flexibility in building the layout of your DataForm, an DataField Group allows you to position editors in a layout panel that is just below the group's header and above the expandable portion of the group. To implement this scenario you need to define a Grid element that will hold the visible editors and position the corresponding DataField instances there:

CopyXAML
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
    <telerikInput:RadDataForm
        EditorCreationMode="CreateByDefault"
        x:Name="radDataForm">
        <Grid>
            <telerikInput:DataFieldGroup Content="Names">
                <telerikInput:DataFieldGroup.VisibleEditorsContent>
                    <Grid>
                        <telerikInput:DataField telerikDataForm:PasswordField.IsPasswordField="True" TargetProperty="Password"/>
                    </Grid>
                </telerikInput:DataFieldGroup.VisibleEditorsContent>
                <Grid>
                    <telerikInput:DataField TargetProperty="FirstName" Grid.Column="0"/>
                    <telerikInput:DataField TargetProperty="SecondName" Grid.Column="1" Grid.Row="0"/>
                </Grid>
            </telerikInput:DataFieldGroup>
            <telerikInput:DataField TargetProperty="ReceivesNewsLetter"/>
            <telerikInput:DataField TargetProperty="DateOfBirth"/>
            <telerikInput:DataField TargetProperty="Gender"/>
        </Grid>
    </telerikInput:RadDataForm>
</Grid>

Here is how the control looks like in this particular scenario:

Data Form Visible Editors 1
Data Form Visible Editors 2

Styling a Data Field Group

The DataFieldGroup inherits from the RadExpanderControl and exposes a Style property. You can style it by creating a Style instance that tagrets the DataFieldGroup type.

Defining a Custom Editor for a Data Field

You can define a custom editor for a DataField. A custom editor will override the default editor which will be created for the associated property according to its type. A custom editor might be any type of user control with custom build UI that generates a value compatible with the associated data property. A custom editor is defined by setting the CustomEditor property to an instance of the CustomEditor class.

The following example demonstrates how creating a custom editor for an enumeration can be done with radio buttons.

We will first create a UserControl that will contain all needed controls for building the editor:

CopyXAML
<UserControl x:Class="DataFormHelpSource.CustomEnumEditor"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    FontFamily="{StaticResource PhoneFontFamilyNormal}"
    FontSize="{StaticResource PhoneFontSizeNormal}"
    Foreground="{StaticResource PhoneForegroundBrush}"
    d:DesignHeight="480" d:DesignWidth="480">

    <Grid x:Name="LayoutRoot">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition/>
            </Grid.ColumnDefinitions>
        <RadioButton Content="Female" Checked="RadioButton_Checked"/>
        <RadioButton Grid.Column="1" Content="Male" Checked="RadioButton_Checked"/>
    </Grid>
</UserControl>

In the code of the editor we need to define a property which will be synchronized with the property on the business object and to add some logic that will define the value of that property:

CopyC#
public partial class CustomEnumEditor : UserControl
{
    public CustomEnumEditor()
    {
        InitializeComponent();
    }

    public DataFormHelpSource.User.UserGender Gender
    {
        get;
        set;
    }

    private void RadioButton_Checked(object sender, System.Windows.RoutedEventArgs e)
    {
        this.Gender = (sender as RadioButton).Content == "Male" ? DataFormHelpSource.User.UserGender.Male : User.UserGender.Female;
    }
}

After having a functional user control that implements the logic of the editor, we need to instruct RadDataForm to use this editor for our property. This is done by setting the CustomEditor property of the corresponding DataField to an instance of the CustomEditor class as follows:

CopyXAML
<telerikInput:DataField TargetProperty="Gender">
    <telerikInput:DataField.CustomEditor>
        <telerikDataForm:CustomEditor>
            <local:CustomEnumEditor 
                telerikDataForm:CustomDataField.EditorValuePath="Gender"
                telerikDataForm:CustomDataField.IsEditor="True"/>
        </telerikDataForm:CustomEditor>
    </telerikInput:DataField.CustomEditor>
</telerikInput:DataField>

By defining the IsEditor and EditorValuePath attached properties we specify which element withing the custom editor element tree will be the editor control and which property on it will be used to retrieve the editor value.

Custom Editors and Value Composers

Another possible way to implement a Custom Editor is to define the editor structure directly to the EditorRoot property of the CustomEditor element in XAML and mark the editor elements by again using the CustomDataField.IsEditor attached property. Then, you specify a ICustomEditorValueDelegate implementation which will be used to synch values back and forth between the target property on the business object and the value properties on the elements designated as editors. The following XAML code demonstrates this:

CopyXAML
<telerikInput:DataField TargetProperty="Gender">
    <telerikInput:DataField.CustomEditor>
        <telerikDataForm:CustomEditor>
            <StackPanel Orientation="Horizontal">
                <RadioButton Content="Male" teleriKDataForm:CustomDataField.IsEditor="True"/>
                <RadioButton Content="Female" teleriKDataForm:CustomDataField.IsEditor="True"/>
            </StackPanel>
            <telerikDataForm:CustomEditor.ValueDelegate>
                <local:GenderValueComposer/>
            </telerikDataForm:CustomEditor.ValueDelegate>
        </telerikDataForm:CustomEditor>
    </telerikInput:DataField.CustomEditor>
</telerikInput:DataField>

In this case defining CustomDataField.EditorValuePath is not needed. Here comes the ICustomEditorValueDelegate:

CopyC#
public class GenderValueComposer : ICustomEditorValueDelegate
{
    /// <summary>
    /// Composes the value.
    /// </summary>
    /// <param name="editors">The editors.</param>
    /// <returns></returns>
    public object ComposeValue(System.Collections.Generic.IEnumerable<DependencyObject> editors)
    {
        DataFormHelpSource.User.UserGender value = User.UserGender.Male;
        foreach (RadioButton btn in editors)
        {
            if (btn.Content.ToString() == "Female" && (bool)btn.IsChecked)
            {
                return User.UserGender.Female;
            }
        }

        return value;
    }


    /// <summary>
    /// Synches the editors value.
    /// </summary>
    /// <param name="propertyValue">The property value.</param>
    /// <param name="editors">The editors.</param>
    public void SynchEditorsValue(object propertyValue, System.Collections.Generic.IEnumerable<DependencyObject> editors)
    {
        DataFormHelpSource.User.UserGender value = (DataFormHelpSource.User.UserGender)propertyValue;

        foreach (RadioButton btn in editors)
        {
            if (btn.Content.ToString() == "Female" && value == User.UserGender.Female)
            {
                btn.IsChecked = true;
            }

            if (btn.Content.ToString() == "Male" && value == User.UserGender.Male)
            {
                btn.IsChecked = true;
            }
        }
    }
}

Once the input information in the RadDataForm instance is committed, the ICustomEditorValueDelegate.ComposeValue method will be used to generate the value for the target property. In this method you will be passed a list of all elements marked as editors in the custom editor's element tree.

The ICustomEditorValueDelegate.SynchEditorsValue method, on the other side, is used to synchronize the value of the editors in the custom editor's element tree with the value of the property on the target business object.

Defining Attributes for Data Fields in XAML

You can use the DataField.AttributeSet property to define property attributes for the property associated with a given DataField. For example, an alternative way to define the FieldInfo attribute is shown below:

CopyXAML
<telerikInput:DataField TargetProperty="Password" telerikDataForm:PasswordField.IsPasswordField="True">
    <telerikInput:DataField.AttributeSet>
        <telerikDataForm:AttributeSet>
            <telerikDataForm:FieldInfoAttribute FieldHeader="Enter password:"/>
        </telerikDataForm:AttributeSet>
    </telerikInput:DataField.AttributeSet>
</telerikInput:DataField>