Archive

Posts Tagged ‘DataForm’

Problems customizing the layout of a DataForm using a Grid – Part III

July 22, 2010 1 comment

So let’s move on to a little more complicated scenario where we have a master detail layout all within the same DataForm. I like to embed all of my data entry layout within the same DataForm so that it can be tracked and submitted back using WCF RIA Services. We will continue to use the same object model from the last two posts.

Again we will start with our beloved Grid and perform the same layout as before with a new row underneath that will show our detail. For the detail, I am just creating a TabControl with a single TabItem and a DataGrid bound to the same object model collection.

<UserControl x:Class="SilverlightApplication2.MainPage"
    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"
    d:DesignHeight="300" d:DesignWidth="400"
    xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"
    xmlns:toolkit="http://schemas.microsoft.com/winfx/2006/xaml/presentation/toolkit"
    xmlns:l="clr-namespace:SilverlightApplication2.Models"
    >
    <UserControl.Resources>
		<DataTemplate x:Key="DataFormGridTemplate">
			<Grid>
				<Grid.ColumnDefinitions>
					<ColumnDefinition Width="Auto" />
					<ColumnDefinition Width="Auto" />
				</Grid.ColumnDefinitions>
				<Grid.RowDefinitions>
					<RowDefinition Height="Auto"/>
					<RowDefinition Height="Auto"/>
					<RowDefinition Height="Auto"/>
					<RowDefinition Height="*"/>
				</Grid.RowDefinitions>
				<toolkit:DataField Label="First Name" Grid.Column="0" Grid.Row="0">
					<TextBox Text="{Binding FirstName, Mode=TwoWay}" />
				</toolkit:DataField>
				<toolkit:DataField Label="Last Name" Grid.Column="0" Grid.Row="1">
					<TextBox Text="{Binding LastName, Mode=TwoWay}" />
				</toolkit:DataField>
				<toolkit:DataField Label="Business Name" Grid.Column="1" Grid.Row="0">
					<TextBox Text="{Binding BusinessName, Mode=TwoWay}" />
				</toolkit:DataField>
				<toolkit:DataField Label="Bio of Business" Grid.Column="1" Grid.Row="1">
					<TextBox Text="{Binding BusinessBio, Mode=TwoWay}" />
				</toolkit:DataField>
				<toolkit:DataField Label="Fax" Grid.Column="0" Grid.Row="2">
					<TextBox Text="{Binding Fax, Mode=TwoWay}" />
				</toolkit:DataField>
				<toolkit:DataField Label="Phone" Grid.Column="1" Grid.Row="2">
					<TextBox Text="{Binding Phone, Mode=TwoWay}" />
				</toolkit:DataField>

                		<sdk:TabControl Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="2">
                    			<sdk:TabControl.Items>
                        			<sdk:TabItem Header="Test 1">
                            				<sdk:DataGrid MinHeight="200" 
								HorizontalAlignment="Left" 
								VerticalAlignment="Top">
                                				<sdk:DataGrid.ItemsSource>
                                    					<l:Customers />
                                				</sdk:DataGrid.ItemsSource>
                            				</sdk:DataGrid>
			                        </sdk:TabItem>
		                    </sdk:TabControl.Items>
                		</sdk:TabControl>
			</Grid>
		</DataTemplate>
    </UserControl.Resources>
    <Grid x:Name="LayoutRoot" Background="White">
        <toolkit:DataForm Header="Data Entry Sample"
			AutoGenerateFields="False"
			ReadOnlyTemplate="{StaticResource DataFormGridTemplate}"
			EditTemplate="{StaticResource DataFormGridTemplate}"
            >
            <toolkit:DataForm.ItemsSource>
                <l:Customers />
            </toolkit:DataForm.ItemsSource>
        </toolkit:DataForm>
	</Grid>
</UserControl>

When we render this DataTemplate, you will notice that the space between the two columns has stretched out to accommodate the width of the DataGrid. We will come back to this:

DataForm using a Grid with Master Detail layout

Now let’s look at how what the template would like for the StackPanel:

<UserControl x:Class="SilverlightApplication2.MainPage"
    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"
    d:DesignHeight="300" d:DesignWidth="400"
    xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"
    xmlns:toolkit="http://schemas.microsoft.com/winfx/2006/xaml/presentation/toolkit"
    xmlns:l="clr-namespace:SilverlightApplication2.Models"
    >
    <UserControl.Resources>
        <DataTemplate x:Key="DataFormStackPanelTemplate">
			<StackPanel>
				<StackPanel Orientation="Horizontal">
					<StackPanel toolkit:DataField.IsFieldGroup="True">
						<toolkit:DataField Label="First Name">
							<TextBox Text="{Binding FirstName, Mode=TwoWay}" />
						</toolkit:DataField>
						<toolkit:DataField Label="Last Name">
							<TextBox Text="{Binding LastName, Mode=TwoWay}" />
						</toolkit:DataField>
						<toolkit:DataField Label="Fax">
							<TextBox Text="{Binding Fax, Mode=TwoWay}" />
						</toolkit:DataField>
					</StackPanel>
					<StackPanel toolkit:DataField.IsFieldGroup="True">
						<toolkit:DataField Label="Business Name">
							<TextBox Text="{Binding BusinessName, Mode=TwoWay}" />
						</toolkit:DataField>
						<toolkit:DataField Label="Bio of Business">
							<TextBox Text="{Binding BusinessBio, Mode=TwoWay}" />
						</toolkit:DataField>
						<toolkit:DataField Label="Phone">
							<TextBox Text="{Binding Phone, Mode=TwoWay}" />
						</toolkit:DataField>
					</StackPanel>
				</StackPanel>
				<StackPanel toolkit:DataField.IsFieldGroup="True">
					<sdk:TabControl>
						<sdk:TabControl.Items>
							<sdk:TabItem Header="Test 1">
								<sdk:DataGrid MinHeight="200" HorizontalAlignment="Left" VerticalAlignment="Top">
									<sdk:DataGrid.ItemsSource>
										<l:Customers />
									</sdk:DataGrid.ItemsSource>
								</sdk:DataGrid>
							</sdk:TabItem>
						</sdk:TabControl.Items>
					</sdk:TabControl>
				</StackPanel>
			</StackPanel>
        </DataTemplate>
    </UserControl.Resources>
    <Grid x:Name="LayoutRoot" Background="White">
        <toolkit:DataForm Header="Data Entry Sample"
			AutoGenerateFields="False"
			ReadOnlyTemplate="{StaticResource DataFormStackPanelTemplate}"
			EditTemplate="{StaticResource DataFormStackPanelTemplate}"
			>
            <toolkit:DataForm.ItemsSource>
                <l:Customers />
            </toolkit:DataForm.ItemsSource>
        </toolkit:DataForm>
	</Grid>
</UserControl>

When we render this out, we get the what we would expect in the layout:

DataForm using a StackPanel with Master Detail layout

So what am missing in the Grid template? The problem is that I have only defined two Column definitions with their value set to “Auto”. All we need to do is add another Column definition with its width set to “*”. The following Grid template shows how to remedy this issue:

<UserControl x:Class="SilverlightApplication2.MainPage"
    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"
    d:DesignHeight="300" d:DesignWidth="400"
    xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"
    xmlns:toolkit="http://schemas.microsoft.com/winfx/2006/xaml/presentation/toolkit"
    xmlns:l="clr-namespace:SilverlightApplication2.Models"
    >
    <UserControl.Resources>
		<DataTemplate x:Key="DataFormGridTemplate">
			<Grid>
				<Grid.ColumnDefinitions>
					<ColumnDefinition Width="Auto" />
					<ColumnDefinition Width="Auto" />
					<ColumnDefinition Width="*" />
				</Grid.ColumnDefinitions>
				<Grid.RowDefinitions>
					<RowDefinition Height="Auto"/>
					<RowDefinition Height="Auto"/>
					<RowDefinition Height="Auto"/>
					<RowDefinition Height="*"/>
				</Grid.RowDefinitions>
				<toolkit:DataField Label="First Name" Grid.Column="0" Grid.Row="0">
					<TextBox Text="{Binding FirstName, Mode=TwoWay}" />
				</toolkit:DataField>
				<toolkit:DataField Label="Last Name" Grid.Column="0" Grid.Row="1">
					<TextBox Text="{Binding LastName, Mode=TwoWay}" />
				</toolkit:DataField>
				<toolkit:DataField Label="Business Name" Grid.Column="1" Grid.Row="0">
					<TextBox Text="{Binding BusinessName, Mode=TwoWay}" />
				</toolkit:DataField>
				<toolkit:DataField Label="Bio of Business" Grid.Column="1" Grid.Row="1">
					<TextBox Text="{Binding BusinessBio, Mode=TwoWay}" />
				</toolkit:DataField>
				<toolkit:DataField Label="Fax" Grid.Column="0" Grid.Row="2">
					<TextBox Text="{Binding Fax, Mode=TwoWay}" />
				</toolkit:DataField>
				<toolkit:DataField Label="Phone" Grid.Column="1" Grid.Row="2">
					<TextBox Text="{Binding Phone, Mode=TwoWay}" />
				</toolkit:DataField>

                		<sdk:TabControl Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="3">
                    			<sdk:TabControl.Items>
                        			<sdk:TabItem Header="Test 1">
                            				<sdk:DataGrid MinHeight="200" 
								HorizontalAlignment="Left" 
								VerticalAlignment="Top">
                                				<sdk:DataGrid.ItemsSource>
                                    					<l:Customers />
                                				</sdk:DataGrid.ItemsSource>
                            				</sdk:DataGrid>
			                        </sdk:TabItem>
		                    </sdk:TabControl.Items>
                		</sdk:TabControl>
			</Grid>
		</DataTemplate>
    </UserControl.Resources>
    <Grid x:Name="LayoutRoot" Background="White">
        <toolkit:DataForm Header="Data Entry Sample"
			AutoGenerateFields="False"
			ReadOnlyTemplate="{StaticResource DataFormGridTemplate}"
			EditTemplate="{StaticResource DataFormGridTemplate}"
            >
            <toolkit:DataForm.ItemsSource>
                <l:Customers />
            </toolkit:DataForm.ItemsSource>
        </toolkit:DataForm>
	</Grid>
</UserControl>

So I added a new Column definition and I also updated the ColumnSpan of the TabControl from “2” to “3”. That it! Let’s take a look at what the output would be:

DataForm using a Grid with Master Detail adjusted layout

So hopefully you can see some of the areas that you need to be aware of when you start making your layout a little advanced.

Note: It is worth noting that the StackPanel approach with the IsFieldGroup attribute is better in my opinion because it will also constrain your TabStop of your controls to follow the contraints of the group and then move to another. I have found that if I get my Grid layout mixed up, that my TabStops go crazy. This is easy to fix but I find that the grouping is sometimes easier.

Hope this helps…

Problems customizing the layout of a DataForm using a Grid – Part II

July 22, 2010 1 comment

I had a great comment from my good friend Karl Shifflett yesterday pointing out that if I would only put in “Auto” or a fixed size in the Width and Height of my Column and Row definitions, the DataForm would like as expected using the Grid.

Note: We will use the same object model that was presented in the last post.

Let’s review what I originally put and then see how it looks with a little more attention to the Column and Row definitions:

<UserControl x:Class="SilverlightApplication2.MainPage"
    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"
    d:DesignHeight="300" d:DesignWidth="400"
    xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"
    xmlns:toolkit="http://schemas.microsoft.com/winfx/2006/xaml/presentation/toolkit"
    xmlns:l="clr-namespace:SilverlightApplication2.Models"
    >
    <UserControl.Resources>
		<DataTemplate x:Key="DataFormGridTemplate">
			<Grid>
				<Grid.ColumnDefinitions>
					<ColumnDefinition />
					<ColumnDefinition />
				</Grid.ColumnDefinitions>
				<Grid.RowDefinitions>
					<RowDefinition />
					<RowDefinition />
					<RowDefinition />
				</Grid.RowDefinitions>
				<toolkit:DataField Label="First Name" Grid.Column="0" Grid.Row="0">
					<TextBox Text="{Binding FirstName, Mode=TwoWay}" />
				</toolkit:DataField>
				<toolkit:DataField Label="Last Name" Grid.Column="0" Grid.Row="1">
					<TextBox Text="{Binding LastName, Mode=TwoWay}" />
				</toolkit:DataField>
				<toolkit:DataField Label="Business Name" Grid.Column="1" Grid.Row="0">
					<TextBox Text="{Binding BusinessName, Mode=TwoWay}" />
				</toolkit:DataField>
				<toolkit:DataField Label="Bio of Business" Grid.Column="1" Grid.Row="1">
					<TextBox Text="{Binding BusinessBio, Mode=TwoWay}" />
				</toolkit:DataField>
				<toolkit:DataField Label="Fax" Grid.Column="0" Grid.Row="2">
					<TextBox Text="{Binding Fax, Mode=TwoWay}" />
				</toolkit:DataField>
				<toolkit:DataField Label="Phone" Grid.Column="1" Grid.Row="2">
					<TextBox Text="{Binding Phone, Mode=TwoWay}" />
				</toolkit:DataField>
			</Grid>
		</DataTemplate>
    </UserControl.Resources>
    <Grid x:Name="LayoutRoot" Background="White">
        <toolkit:DataForm Header="Data Entry Sample"
			AutoGenerateFields="False"
			ReadOnlyTemplate="{StaticResource DataFormGridTemplate}"
			EditTemplate="{StaticResource DataFormGridTemplate}"
            >
            <toolkit:DataForm.ItemsSource>
                <l:Customers />
            </toolkit:DataForm.ItemsSource>
        </toolkit:DataForm>
	</Grid>
</UserControl>

Like in the last post, my template produces the following output:

DataForm Grid Template

Now let’s just add a little more detail to the Column and Row definitions:

<UserControl x:Class="SilverlightApplication2.MainPage"
    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"
    d:DesignHeight="300" d:DesignWidth="400"
    xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"
    xmlns:toolkit="http://schemas.microsoft.com/winfx/2006/xaml/presentation/toolkit"
    xmlns:l="clr-namespace:SilverlightApplication2.Models"
    >
    <UserControl.Resources>
		<DataTemplate x:Key="DataFormGridTemplate">
			<Grid>
				<Grid.ColumnDefinitions>
					<ColumnDefinition Width="Auto" />
					<ColumnDefinition Width="Auto" />
				</Grid.ColumnDefinitions>
				<Grid.RowDefinitions>
					<RowDefinition Height="Auto"/>
					<RowDefinition Height="Auto"/>
					<RowDefinition Height="Auto" />
				</Grid.RowDefinitions>
				<toolkit:DataField Label="First Name" Grid.Column="0" Grid.Row="0">
					<TextBox Text="{Binding FirstName, Mode=TwoWay}" />
				</toolkit:DataField>
				<toolkit:DataField Label="Last Name" Grid.Column="0" Grid.Row="1">
					<TextBox Text="{Binding LastName, Mode=TwoWay}" />
				</toolkit:DataField>
				<toolkit:DataField Label="Business Name" Grid.Column="1" Grid.Row="0">
					<TextBox Text="{Binding BusinessName, Mode=TwoWay}" />
				</toolkit:DataField>
				<toolkit:DataField Label="Bio of Business" Grid.Column="1" Grid.Row="1">
					<TextBox Text="{Binding BusinessBio, Mode=TwoWay}" />
				</toolkit:DataField>
				<toolkit:DataField Label="Fax" Grid.Column="0" Grid.Row="2">
					<TextBox Text="{Binding Fax, Mode=TwoWay}" />
				</toolkit:DataField>
				<toolkit:DataField Label="Phone" Grid.Column="1" Grid.Row="2">
					<TextBox Text="{Binding Phone, Mode=TwoWay}" />
				</toolkit:DataField>
			</Grid>
		</DataTemplate>
    </UserControl.Resources>
    <Grid x:Name="LayoutRoot" Background="White">
        <toolkit:DataForm Header="Data Entry Sample"
			AutoGenerateFields="False"
			ReadOnlyTemplate="{StaticResource DataFormGridTemplate}"
			EditTemplate="{StaticResource DataFormGridTemplate}"
            >
            <toolkit:DataForm.ItemsSource>
                <l:Customers />
            </toolkit:DataForm.ItemsSource>
        </toolkit:DataForm>
	</Grid>
</UserControl>

Now we get the output that we would normally expect:

DataForm using a Grid with Column and Row definitions

So it looks like you can use either a Grid or StackPanel to manage your layout. We shall see….

Stay tuned for the next post and let’s see if we can solve my next opportunity.

Problems customizing the layout of a DataForm using a Grid.

July 22, 2010 1 comment

The DataForm is a pretty powerful control. It comes built with a lot of functionality that you don’t need to write multiple times. One of the things I do a lot with the DataForm is override the ReadOnly and Edit templates. In this post I am going to show a simple model class that would represent a Customer object and collection. I will then go into the using the AutoGeneration=”True” attribute of the DataForm. Finally, I will walk you through two paths of customizing the look and feel of the DataForm. The first path seemed to me to be the better of the two but as we look at the output we will quickly realize that the latter is by far the better.

Okay so lets first examine the data object we will be using in your example:

namespace DataFormSample.Models
{
    public class Customer
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string BusinessName { get; set; }
        public string BusinessBio { get; set; }
        public string Fax { get; set; }
        public string Phone { get; set; }
    };
    public class Customers : ObservableCollection<Customer>
    {
        public Customers()
        {
            Customer c = new Customer()
            {
                FirstName = "George",
                LastName = "Washington",
                BusinessName = "Washington Mutual",
                BusinessBio = "This company specializes in watching your money.",
                Phone = "8005551212",
                Fax = "8005551213"
            };
            this.Add(c);
            c = new Customer()
            {
                FirstName = "Abraham",
                LastName = "Lincoln",
                BusinessName = "Lincoln Cabins",
                BusinessBio = "Good lodging for good folk.",
                Phone = "8005558100",
                Fax = "8005558101"
            };
            this.Add(c);

        }
    };
}

As you can see from the source code, I am exposing two classes. The first class is just a simple data transfer object with the name of Customer. The other class is a sample hydrated ObservableCollection that will act as the ItemsSource of the DataForm. You can see that I have added two records.

We will now look at the XAML required to get this class wired up to a DataForm with the AutoGenerateFields attribute set to “True”.

<UserControl x:Class="SilverlightApplication2.MainPage"
    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"
    d:DesignHeight="300" d:DesignWidth="400"
    xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"
    xmlns:toolkit="http://schemas.microsoft.com/winfx/2006/xaml/presentation/toolkit"
    xmlns:l="clr-namespace:SilverlightApplication2.Models"
    >
    <Grid x:Name="LayoutRoot" Background="White">
        <toolkit:DataForm Header="Data Entry Sample"
                          AutoGenerateFields="True">
            <toolkit:DataForm.ItemsSource>
                <l:Customers />
            </toolkit:DataForm.ItemsSource>
        </toolkit:DataForm>
	</Grid>
</UserControl>

When the sample appliation is run the output looks like this:

DataForm with AutoGenerateFields='True'

As you can see, the DataForm is great for generating simple admin screens. It doesn’t really look like something that you would want to throw in front of a client though.

Let’s look at the next set of approaches that will have the AutoGenerateFields attribute set to “False”.

The first example of XAML involves using a Grid for managing the layout in a DataForm:

<UserControl x:Class="SilverlightApplication2.MainPage"
    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"
    d:DesignHeight="300" d:DesignWidth="400"
    xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"
    xmlns:toolkit="http://schemas.microsoft.com/winfx/2006/xaml/presentation/toolkit"
    xmlns:l="clr-namespace:SilverlightApplication2.Models"
    >
    <UserControl.Resources>
		<DataTemplate x:Key="DataFormGridTemplate">
			<Grid>
				<Grid.ColumnDefinitions>
					<ColumnDefinition />
					<ColumnDefinition />
				</Grid.ColumnDefinitions>
				<Grid.RowDefinitions>
					<RowDefinition />
					<RowDefinition />
					<RowDefinition />
				</Grid.RowDefinitions>
				<toolkit:DataField Label="First Name" Grid.Column="0" Grid.Row="0">
					<TextBox Text="{Binding FirstName, Mode=TwoWay}" />
				</toolkit:DataField>
				<toolkit:DataField Label="Last Name" Grid.Column="0" Grid.Row="1">
					<TextBox Text="{Binding LastName, Mode=TwoWay}" />
				</toolkit:DataField>
				<toolkit:DataField Label="Business Name" Grid.Column="1" Grid.Row="0">
					<TextBox Text="{Binding BusinessName, Mode=TwoWay}" />
				</toolkit:DataField>
				<toolkit:DataField Label="Bio of Business" Grid.Column="1" Grid.Row="1">
					<TextBox Text="{Binding BusinessBio, Mode=TwoWay}" />
				</toolkit:DataField>
				<toolkit:DataField Label="Fax" Grid.Column="0" Grid.Row="2">
					<TextBox Text="{Binding Fax, Mode=TwoWay}" />
				</toolkit:DataField>
				<toolkit:DataField Label="Phone" Grid.Column="1" Grid.Row="2">
					<TextBox Text="{Binding Phone, Mode=TwoWay}" />
				</toolkit:DataField>
			</Grid>
		</DataTemplate>
    </UserControl.Resources>
    <Grid x:Name="LayoutRoot" Background="White">
        <toolkit:DataForm Header="Data Entry Sample"
			AutoGenerateFields="False"
			ReadOnlyTemplate="{StaticResource DataFormGridTemplate}"
			EditTemplate="{StaticResource DataFormGridTemplate}"
            >
            <toolkit:DataForm.ItemsSource>
                <l:Customers />
            </toolkit:DataForm.ItemsSource>
        </toolkit:DataForm>
	</Grid>
</UserControl>

This time when we run the application, the output looks like this:

DataForm Grid Template

Clearly something is wrong with the way I wrote that DataTemplate.

Update: It turns out that this is not at all a problem with the DataForm. It is merely an issue with my Grid definition. Please see Part II for further clarification.

Let’s take a look at the DataTemplate when it is outside of the DataForm:

<UserControl x:Class="SilverlightApplication2.MainPage"
    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"
    d:DesignHeight="300" d:DesignWidth="400"
    xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"
    xmlns:toolkit="http://schemas.microsoft.com/winfx/2006/xaml/presentation/toolkit"
    xmlns:l="clr-namespace:SilverlightApplication2.Models"
    >
    <UserControl.Resources>
		<DataTemplate x:Key="DataFormGridTemplate">
			<Grid>
				<Grid.ColumnDefinitions>
					<ColumnDefinition />
					<ColumnDefinition />
				</Grid.ColumnDefinitions>
				<Grid.RowDefinitions>
					<RowDefinition />
					<RowDefinition />
					<RowDefinition />
				</Grid.RowDefinitions>
				<toolkit:DataField Label="First Name" Grid.Column="0" Grid.Row="0">
					<TextBox Text="{Binding FirstName, Mode=TwoWay}" />
				</toolkit:DataField>
				<toolkit:DataField Label="Last Name" Grid.Column="0" Grid.Row="1">
					<TextBox Text="{Binding LastName, Mode=TwoWay}" />
				</toolkit:DataField>
				<toolkit:DataField Label="Business Name" Grid.Column="1" Grid.Row="0">
					<TextBox Text="{Binding BusinessName, Mode=TwoWay}" />
				</toolkit:DataField>
				<toolkit:DataField Label="Bio of Business" Grid.Column="1" Grid.Row="1">
					<TextBox Text="{Binding BusinessBio, Mode=TwoWay}" />
				</toolkit:DataField>
				<toolkit:DataField Label="Fax" Grid.Column="0" Grid.Row="2">
					<TextBox Text="{Binding Fax, Mode=TwoWay}" />
				</toolkit:DataField>
				<toolkit:DataField Label="Phone" Grid.Column="1" Grid.Row="2">
					<TextBox Text="{Binding Phone, Mode=TwoWay}" />
				</toolkit:DataField>
			</Grid>
		</DataTemplate>
    </UserControl.Resources>
    <Grid x:Name="LayoutRoot" Background="White">
        <ContentControl Content="{Binding Customer}"
			ContentTemplate="{StaticResource DataFormGridTemplate}">
            <ContentControl.DataContext>
                <l:CustomerSample />
            </ContentControl.DataContext>
        </ContentControl>
	</Grid>
</UserControl>

When run we get this output which looks more like what I would have expected:

Grid Template

So is there something inherently wrong with the DataForm? It took me some time to stop staring at my DataTemplate and start examing what the documentation showed for building custom layout for the DataForm.

It turns out that the following DataTemplate example is the best suited for the DataForm:

<UserControl x:Class="SilverlightApplication2.MainPage"
    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"
    d:DesignHeight="300" d:DesignWidth="400"
    xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"
    xmlns:toolkit="http://schemas.microsoft.com/winfx/2006/xaml/presentation/toolkit"
    xmlns:l="clr-namespace:SilverlightApplication2.Models"
    >
    <UserControl.Resources>
        <DataTemplate x:Key="DataFormStackPanelTemplate">
            <StackPanel Orientation="Horizontal">
                <StackPanel toolkit:DataField.IsFieldGroup="True">
                    <toolkit:DataField Label="First Name">
                        <TextBox Text="{Binding FirstName, Mode=TwoWay}" />
                    </toolkit:DataField>
                    <toolkit:DataField Label="Last Name">
                        <TextBox Text="{Binding LastName, Mode=TwoWay}" />
                    </toolkit:DataField>
                    <toolkit:DataField Label="Fax">
                        <TextBox Text="{Binding Fax, Mode=TwoWay}" />
                    </toolkit:DataField>
                </StackPanel>
                <StackPanel toolkit:DataField.IsFieldGroup="True">
                    <toolkit:DataField Label="Business Name">
                        <TextBox Text="{Binding BusinessName, Mode=TwoWay}" />
                    </toolkit:DataField>
                    <toolkit:DataField Label="Bio of Business">
                        <TextBox Text="{Binding BusinessBio, Mode=TwoWay}" />
                    </toolkit:DataField>
                    <toolkit:DataField Label="Phone">
                        <TextBox Text="{Binding Phone, Mode=TwoWay}" />
                    </toolkit:DataField>
                </StackPanel>
            </StackPanel>
        </DataTemplate>
    </UserControl.Resources>
    <Grid x:Name="LayoutRoot" Background="White">
        <toolkit:DataForm Header="Data Entry Sample"
			AutoGenerateFields="False"
			ReadOnlyTemplate="{StaticResource DataFormStackPanelTemplate}"
			EditTemplate="{StaticResource DataFormStackPanelTemplate}"
			>
            <toolkit:DataForm.ItemsSource>
                <l:Customers />
            </toolkit:DataForm.ItemsSource>
        </toolkit:DataForm>
	</Grid>
</UserControl>

When run, we get this output as expected:

DataForm StackPanel Template

So the secret is in the sauce! Well not really it is actually a little attached property that tells the StackPanel that it is in a FieldGroup. Once you have that in place, you should be able to author your custom DataForm layouts to your heart’s desire.

Note: It may seem like this is an intuitive problem but I was certain that I was doing something wrong with my Grid and it took me way too long to solve this. I personally lean towards using the Grid as a carpentar would lean toward this hammer.

Hope this helps you and keeps you from any frustrations that I have already had! 🙂