Let's create a very simple master/details screen to allow the user to edit product data.
EditProductsView.xaml
.LayoutRoot
Grid vertically into two rows.
<navigation:Page x:Class="AdventureWorks.Views.EditProductsView"
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"
xmlns:navigation="clr-namespace:System.Windows.Controls;
assembly=System.Windows.Controls.Navigation"
mc:Ignorable="d"
d:DesignWidth="640" d:DesignHeight="480"
Title="Edit Products">
<Grid x:Name="LayoutRoot">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
</Grid>
</navigation:Page>
xmlns:riaControls="clr-namespace:System.Windows.Controls;
assembly=System.Windows.Controls.DomainServices"
xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"
xmlns:toolkit=
"http://schemas.microsoft.com/winfx/2006/xaml/presentation/toolkit"
xmlns:my="clr-namespace:AdventureWorks.Web"
xmlns:my1="clr-namespace:AdventureWorks.Web.Services"
LayoutRoot
Grid control, and hook it up to the GetProducts
domain operation exposed by the ProductService
domain service that you created in Chapter 4.
<riaControls:DomainDataSource AutoLoad="True" Height="0" Width="0"
d:DesignData="{d:DesignInstance my:Product, CreateList=true}"
Name="productDDS" QueryName="GetProductsQuery">
<riaControls:DomainDataSource.DomainContext>
<my1:ProductContext />
</riaControls:DomainDataSource.DomainContext>
</riaControls:DomainDataSource>
LayoutRoot
Grid, and bind its ItemsSource
property to the DomainDataSource control.
<sdk:DataGrid ItemsSource="{Binding ElementName=productDDS, Path=Data}" />
LayoutRoot
Grid, which we'll use to lay out our data entry form. The following XAML demonstrates a simple data entry form that allows you to edit five properties on a Product
entity. It includes three text boxes (one which formats how the value should be displayed using the Binding
object's StringFormat
property), and two DatePicker controls. It also includes a ValidationSummary control to display the details of any data validation errors, hence the need for all the bindings to have their NotifyOnValidationError
set to True
so that the ValidationSummary control can be made aware of their validation errors.
<Grid Grid.Row="1" DataContext="{Binding ElementName=productDDS, Path=Data}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100" />
<ColumnDefinition Width="250" />
</Grid.ColumnDefinitions>
<sdk:Label Grid.Row="0" Content="Name:"
Target="{Binding ElementName=NameField}" />
<sdk:Label Grid.Row="1" Content="Product Number:"
Target="{Binding ElementName=ProductNumberField}" />
<sdk:Label Grid.Row="2" Content="List Price:"
Target="{Binding ElementName=ListPriceField}" />
<sdk:Label Grid.Row="3" Content="Sell Start Date:"
Target="{Binding ElementName=SellStartDate}" />
<sdk:Label Grid.Row="4" Content="Sell End Date:"
Target="{Binding ElementName=SellEndDate}" />
<TextBox Name="NameField" Grid.Column="1" Grid.Row="0" Margin="2"
Text="{Binding Name, Mode=TwoWay,
NotifyOnValidationError=True}" />
<TextBox Name="ProductNumberField" Grid.Column="1" Grid.Row="1" Margin="2"
Text="{Binding ProductNumber, Mode=TwoWay,
NotifyOnValidationError=True}" />
<TextBox Name="ListPriceField"
Grid.Column="1" Grid.Row="2" Margin="2"
Text="{Binding ListPrice, Mode=TwoWay, StringFormat=C,
NotifyOnValidationError=True}" />
<sdk:DatePicker Name="SellStartDateField"
Grid.Column="1" Grid.Row="3" Margin="2"
SelectedDate="{Binding SellStartDate, Mode=TwoWay,
NotifyOnValidationError=True}" />
<sdk:DatePicker Name="SellEndDateField"
Grid.Column="1" Grid.Row="4" Margin="2"
SelectedDate="{Binding SellEndDate, Mode=TwoWay,
NotifyOnValidationError=True}" />
<sdk:ValidationSummary Grid.Row="5" Grid.ColumnSpan="2"
VerticalAlignment="Bottom" />
</Grid>
Note As you can see, we're binding the top-level Grid control's DataContext
property to the collection returned by the DomainDataSource control. The DomainDataSource control's Data
property returns a collection view (a DomainDataSourceView
), which maintains a CurrentItem
property. Controls that expect to be bound to a single object instead of a collection see that they are bound to a collection view, automatically drill down to this property, and bind to the object that it exposes. The DataGrid control is also bound to this same collection view, and when a row is selected in the DataGrid, it will update the collection view's CurrentItem
property accordingly. Therefore, when you select an item in the DataGrid, the details for that item will appear in the data entry form. This synchronization feature provided by collection views is very neat and makes it very easy to implement master/details views.
Name
field), the control will change its appearance to indicate that the data is invalid, and a validation error will appear in the ValidationSummary control. Note The next step is to provide a way to save the changes back to the server, which you can implement by binding a Button control to the DomainDataSource control's SubmitChangesCommand
property, as described in Chapter 5.