Silverlight and RIA Services: Managing Your Codes
Every application has some type of codes: customer types, reason codes, states, and so on. Sometimes these codes can be hard-coded in an application as Enum values. But other times these codes are more readily stored in a table. This post details how to work with code tables through RIA Services.
[For details on how to work with Enum values through RIA Services, see this prior post.]
NOTE: This example continues from this prior post that introduces RIA Services and your business objects.
Building the Business Layer Classes
To manage the codes in your application without having to build a class for each type of code, you can build a more generalized Code class in your business layer. This class is added to the project containing the Customer and Customers classes from this prior post.
In C#:
using System.ComponentModel.DataAnnotations;
namespace BoCSharp
{
public class Code
{
[Key()]
public int CodeId { get; set; }
public string CodeText { get; set; }
}
}
In VB:
Imports System.ComponentModel.DataAnnotations
Public Class Code
Private _CodeId As Integer
<Key()> _
Public Property CodeId() As Integer
Get
Return _CodeId
End Get
Set(ByVal value As Integer)
_CodeId = value
End Set
End Property
Private _CodeText As String
Public Property CodeText() As String
Get
Return _CodeText
End Get
Set(ByVal value As String)
_CodeText = value
End Set
End Property
End Class
Each code has an Id and a text value. The Key() attribute on the CodeId ensures that this class is set up to use RIA Services.
A separate class in the business layer then tracks the sets of all codes.
In C#:
using System.Collections.Generic;
namespace BoCSharp
{
public class Codes
{
public static List<Code> RetrieveCustomerTypes()
{
List<Code> custTypeList = new List<Code>
{new Code()
{CodeId=1,
CodeText="Individual"},
new Code()
{CodeId=2,
CodeText="Corporate"},
new Code()
{CodeId=3,
CodeText="Government"},
new Code()
{CodeId=4,
CodeText="Education"}};
return custTypeList;
}
}
}
In VB:
Public Class Codes
Public Shared Function RetrieveCustomerTypes() As List(Of Code)
Dim custTypeList As New List(Of Code)
custTypeList.Add(New Code With { _
.CodeId = 1, _
.CodeText = "Individual"})
custTypeList.Add(New Code With { _
.CodeId = 2, _
.CodeText = "Corporate"})
custTypeList.Add(New Code With { _
.CodeId = 3, _
.CodeText = "Government"})
custTypeList.Add(New Code With { _
.CodeId = 4, _
.CodeText = "Education"})
Return custTypeList
End Function
End Class
Two things to note about this class:
- It will have a Retrieve method for each kind of code (customer types, reason codes, states, and so on).
- In the "real" application, it will get these values from the database instead of hard-coded values. (Hard-coded values are used here so you don’t have to set up a database to try these techniques.)
Finally, let’s modify the Customer class to add the customer type property. Each customer has a customer type.
In C#:
using System.ComponentModel.DataAnnotations;
namespace BoCSharp
{
public class Customer
{
[Key()]
public int CustomerId { get; set; }
public int CustomerTypeId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string EmailAddress { get; set; }
public Customer()
{
}
}
}
In VB:
Imports System.ComponentModel.DataAnnotations
Public Class Customer
Private _CustomerId As Integer
<Key()> _
Public Property CustomerId() As Integer
Get
Return _CustomerId
End Get
Set(ByVal value As Integer)
_CustomerId = value
End Set
End Property
Private _CustomerTypeId As Integer
Public Property CustomerTypeId() As Integer
Get
Return _CustomerTypeId
End Get
Set(ByVal value As Integer)
_CustomerTypeId = value
End Set
End Property
Private _FirstName As String
Public Property FirstName() As String
Get
Return _FirstName
End Get
Set(ByVal value As String)
_FirstName = value
End Set
End Property
Private _LastName As String
Public Property LastName() As String
Get
Return _LastName
End Get
Set(ByVal value As String)
_LastName = value
End Set
End Property
Private _EmailAddress As String
Public Property EmailAddress() As String
Get
Return _EmailAddress
End Get
Set(ByVal value As String)
_EmailAddress = value
End Set
End Property
End Class
Though only the CustomerTypeId is new, all of the code from the Customer class (originally defined in this prior post) is shown above.
Building the Domain Service Class
The next step is to build a Domain Service class for the Codes class so that the Silverlight project can access the codes.
In C#:
namespace SLCSharp.Web
{
using BoCSharp;
using System.Collections.Generic;
using System.Web.Ria;
using System.Web.DomainServices;
[EnableClientAccess()]
public class CodeService : DomainService
{
public IEnumerable<Code> GetCustomerTypes()
{
return Codes.RetrieveCustomerTypes();
}
}
}
In VB:
Imports System.Web.DomainServices
Imports System.Web.Ria
<EnableClientAccess()> _
Public Class CodeService
Inherits DomainService
Public Function GetCustomerTypes() As IEnumerable(Of Code)
Return Codes.RetrieveCustomerTypes()
End Function
End Class
This class will have a function to expose each type of code. For now, it provides a function to get the customer types.
Accessing the Codes from Silverlight
One of the common ways to use the codes in Silverlight is to present them in a ComboBox. This involves two steps:
- Add a DomainDataSource that accesses the Domain Service class.
- Add a ComboBox that binds to the DomainDataSource.
In XAML:
<UserControl x:Class="SLVB.CodesExampleUC"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:riaControls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Ria.Controls"
xmlns:domain="clr-namespace:SLVB.Web"
Width="400" Height="300">
<Grid x:Name="LayoutRoot" Background="White">
<riaControls:DomainDataSource x:Name="CustomerTypeSource"
QueryName="GetCustomerTypes" AutoLoad="True">
<riaControls:DomainDataSource.DomainContext>
<domain:CodeContext/>
</riaControls:DomainDataSource.DomainContext>
</riaControls:DomainDataSource>
<StackPanel Margin="10">
<ComboBox ItemsSource=
"{Binding Data, ElementName=CustomerTypeSource}"
DisplayMemberPath="CodeText"/>
</StackPanel>
</Grid>
</UserControl>
Using the DomainDataSource requires adding two namespaces to the UserControl:
1) xmlns:riaControls is needed for the RIA DomainDataSource control.
NOTE: You won’t find the DomainDataSource control in the toolbox. You need to type it into the XAML manually.
2) xmlns:domain is the namespace for your Web project that launches your Silverlight application.
Define a name for the DomainDataSource using the x:Name property. This is the name used in the binding. Also set the QueryName property to the name of the Domain Service class method that gets the data for this data source. In this case, it is the GetCustomerTypes method.
The DomainDataSource also requires a DomainContext. This is where you define the name of the data context used by the data source. If you don’t see an appropriate context using intellisense, try rebuilding your application. Otherwise you can type in the name. It will be the same name as your Domain Service class but replacing "Service" with "Context". Since this example Domain Service class is CodeService, the context is CodeContext.
The next set of XAML builds a ComboBox inside a StackPanel. The ItemsSource property of the ComboBox defines the binding to the name of the DomainDataSource. The DisplayMemberPath property is set to the name of the class property to display in the ComboBox. In this case, the ComboBox displays the CodeText property.
The result is as follows:
Use this technique to access your code tables from your Silverlight application.
Enjoy!