Using the Infragistics XamGrid with WCF RIA Services

[Infragistics] Mihail Mateev / Monday, June 7, 2010

This article describes how to use the Infragistics XamGrid with WCF RIA Services.

 

WCF RIA Services simplifies the development of n-tier solutions for Rich Internet Applications (RIA), such as Silverlight applications. A common problem when developing an n-tier RIA solution is coordinating application logic between the middle tier and the presentation tier.

RIA Services adds tools to Visual Studio that enable linking client and server projects in a single solution and generating code for the client project from the middle-tier code.

  

In the NetAdvantage Silverlight Line of Business controls v.10.2 most of controls, including  XamGrid  support WCF RIA Services.

There are several steps to create a demo upload/download application:

  1. Download the trial version of NetAdvantage for Silverlight LoB 10.2*
  2. Install WCF RIA Services for Silverlight 4 and Visual Studio 2010 (it includes also WCF Ria Services)
  3. Create a Silverlight application, hosted in an ASP.Net application with RIA Services link
  4. Create Data Model
  5. Create a Domain Service
  6. Create a Silverlight Client with XamGrid
  7. Add query methods

 * New NetAdvantage for Silverlight Line of Business will be available for download on June, 2010.

In order to successfully compile and run the application you will need to install trial version of NetAdvantage for Silverlight LoB 10.2

 Demo application demonstrates how to create a Silverlight application with RIA services link, add data connection, create ADO.NET Entity Data Model and add Domain Service class.  In the layout of the Silverlight application is added XamGrid component as bound control to the Domain Context object, created automatically in the client application.

 

Requirements:

 

Create a Silverlight Application:

In Visual Studio, create a new Silverlight Application with RIA Services link.

We need to enable WCF RIA Services check box.

 

Create Data Model

 

In this section, you will create the ADO.NET Entity classes that represent data from the Chinook database.

  • Configure Data Connection

Data Connection must be created. For this sample application I'm using the Chinook sample database. You could download it from there:

  • Configure DataSource:

In Solution Explorer, right-click the server project (IGRiaServicesDemo.Web), select Add, and then select New Item.

The Add New Item dialog box appears.

In the list of categories, select Data and then select the ADO.NET Entity Data Model template.

Name the new file ChinookModel.edmx

Confirm generation of the Entity Data Model from a database.

In the Choose Your Data Connection screen, create a data connection to the database.

In the Choose Your Database Objects screen, select the Customer and Employee tables.

Entity models are created for the tables.

Build the solution.

Create a Domain Service

Add a domain service to the middle-tier project. A domain service exposes the data entities and operations in the server project to the client project. You can add business logic to the domain service to manage how the client interacts with the data.

Right-click the server project, select Add and New Item.

In the list of categories, select Web and then select the Domain Service Class template.

Name the class ChinookDomainService.cs .

Confirm Enable editing option for selected tables and pres the "OK" button.

The domain service class is generated.

 

Create the Silverlight Client

 Because a RIA Services link exists between the client project and the server project, client proxy classes are generated when you build the solution. These proxy classes enable you to access the data from the client.

In the hidden folder "Generated_Code" there is a code file where could find several classes:
WebContext,  ChinookDomainContext, Employee and Customer.

 Add the Infragistics XamGrid as default control, bound to our Customer and Employee classes:

In the Data Sources for each table select from the context menu Customize option.

It is possible to add Infragistics Silverlight controls from NetAdvantage 10.2 there:

Select XamGrid and set it as a default control.

In the client application there is created a DataSources folder with an instance of ChinookDomainContext there.

XamGrid is set as a default control for Customer and Employee classes.

Add a Data Source, bound to XamGrid.ItemsSource in the Layout

Drag the Employee class from Data Sources window to the layout of the Silverlight client application.

In the XAML there will be added a DomainDataSource instance and XamGrid object with ItemsSource bound to this DomainDataSource.

 <Grid x:Name="LayoutRoot" Background="White">

<riaControls:DomainDataSource AutoLoad="True" d:DesignData="{d:DesignInstance   my:Employee, CreateList=true}" Height="0"    LoadedData="employeeDomainDataSource_LoadedData" Name="employeeDomainDataSource" QueryName="GetEmployeesQuery" Width="0">
            <riaControls:DomainDataSource.DomainContext>
                <my:ChinookDomainContext />
            </riaControls:DomainDataSource.DomainContext>
   </riaControls:DomainDataSource>
<ig:XamGrid HorizontalAlignment="Left" ItemsSource="{Binding ElementName=employeeDomainDataSource, Path=Data}" Margin="25" Name="employeeXamGrid" VerticalAlignment="Top" />
</Grid>

 Start the application:

Data is loaded in the XamGrid instance.

Create the DomainDataSource and DomainContext from C#  code

If in the XAML file we have only a definition of the XamGrid:

<ig:XamGrid HorizontalAlignment="Left"  Margin="25" Name="employeeXamGrid2" VerticalAlignment="Top" />

It is possible to create the DomainDataSource and its DomainContext from C# code:

public partial class MainPage : UserControl
{
        DomainDataSource _chinookDomainSource = new DomainDataSource();
        private ChinookDomainContext _chinookContext = new ChinookDomainContext();
        public MainPage()
        {
            InitializeComponent();
             _chinookDomainSource.DataContext = _chinookContext;
            _chinookDomainSource.LoadedData += employeeDomainDataSource_LoadedData;
            LoadOperation<Employee> loadOp = this._chinookContext.Load(this._chinookContext.GetEmployeesQuery());
            employeeXamGrid2.ItemsSource = loadOp.Entities;
        }
 
private void employeeDomainDataSource_LoadedData(object sender, System.Windows.Controls.LoadedDataEventArgs e)
 {
 
            if (e.HasError)
            {
                     System.Windows.MessageBox.Show(e.Error.ToString(), "Load Error", System.Windows.MessageBoxButton.OK);
                     e.MarkErrorAsHandled();
            }
}
}

Add Query Methods

In the server project, open the domain service class, named  ChinookDomainService , that exposes data from the Employee table.

 

//Return an employee by his Id
[Query(IsComposable = false)]
public Employee GetEmployeeById(int EmployeeId)
{
return this.ObjectContext.Employees.SingleOrDefault(c => c.EmployeeId == EmployeeId);
}
 
//Return a list of employees by part of its address
public IQueryable<Employee> GetEmployeessByAddressLetter(string startingAddressLetter)
{
return this.ObjectContext.Employees.Where(c => c.Address.StartsWith(startingAddressLetter) == true);
}

Display the results of those query methods in the client project.

Add buttons to search employees by Id , address and restore the default view.

Add ComboBox, bound to the EditingType enum values to control the editing type of the XamGrid, that could be None, Cell and Row.

 <Grid>

    <Grid.ColumnDefinitions>
        <ColumnDefinition/>
        <ColumnDefinition/>
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition/>
        <RowDefinition/>
    </Grid.RowDefinitions>
    <Grid Grid.Column="0">
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <TextBlock Grid.Column="0" Text="search by id: " ></TextBlock>
        <TextBox Grid.Column="1" Name="EmployeeIDValue" Width="80" ></TextBox>
        <Button Grid.Column="2" Name="EmployeeIDButton" Click="EmployeeIdButton_Click" Content="Submit Id"></Button>
    </Grid>
    <Grid  Grid.Column="1">
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <TextBlock Grid.Column="0" Text="Search by address: "></TextBlock>
        <TextBox Grid.Column="1" Name="LetterValue" Width="80"></TextBox>
        <Button Grid.Column="2" Name="LetterButton" Click="LetterButton_Click" Content="Submit Address"></Button>
    </Grid>
    <Grid Grid.Column="0" Grid.Row="1">
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <TextBlock Grid.Column="0" Text="Restore a default view: " Grid.ColumnSpan="2"></TextBlock>
        <Button Grid.Column="2" Name="ResetButton" Click="ResetButton_Click"  Content="Reset Data"></Button>
    </Grid>
    <Grid  Grid.Column="1" Grid.Row="1">
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>               
        <TextBlock Grid.Column="0" Text="Edit mode: "></TextBlock>
        <ComboBox Grid.Column="1" x:Name="ComboEditingType" Width="80" ItemsSource="{Binding EnumValues, ElementName= mainPage}" DisplayMemberPath = "Key"  SelectionChanged="ComboEditingType_SelectionChanged"/>
        <Button Grid.Column="2" Name="UpdateButton" Click="UpdateButton_Click"  Content="Update Changes"></Button>
    </Grid>            
</Grid>

In the C# code there is an implementation in each of the event handlers.

 

#region EmployeeIdButton_Click
//Returns found employee by Id
private void EmployeeIdButton_Click(object sender, RoutedEventArgs e)
{
    ChinookDomainContext employeeContext = this.employeeDomainDataSource.DomainContext as ChinookDomainContext;
    if (employeeContext != null)
    {
        EmployeeIDButton.IsEnabled = false;
        LetterButton.IsEnabled = false;
        LoadOperation<Employee> loadOp =
            employeeContext.Load(employeeContext.GetEmployeeByIdQuery(int.Parse(EmployeeIDValue.Text)),
                                    EmployeeLoadedCallback, null);
        employeeXamGrid.ItemsSource = loadOp.Entities;
    }
}
#endregion //EmployeeIdButton_Click
#region LetterButton_Click
//Returns a list of employees by part of the address
private void LetterButton_Click(object sender, RoutedEventArgs e)
{
    ChinookDomainContext employeeContext = this.employeeDomainDataSource.DomainContext as ChinookDomainContext;
    if (employeeContext != null)
    {
        EmployeeIDButton.IsEnabled = false;
        LetterButton.IsEnabled = false;
         LoadOperation<Employee> loadOp = employeeContext.Load(employeeContext.GetEmployeessByAddressLetterQuery(LetterValue.Text), EmployeeLoadedCallback, null);
        employeeXamGrid.ItemsSource = loadOp.Entities;
    }
 }
#endregion //LetterButton_Click
 
#region ResetButton_Click
//Reset a default view
private void ResetButton_Click(object sender, RoutedEventArgs e)
{
     ChinookDomainContext employeeContext = this.employeeDomainDataSource.DomainContext as ChinookDomainContext;
     if (employeeContext != null)
    {
        EmployeeIDButton.IsEnabled = false;
        LetterButton.IsEnabled = false;
        LoadOperation<Employee> loadOp = employeeContext.Load(employeeContext.GetEmployeesQuery(), EmployeeLoadedCallback, null);
        employeeXamGrid.ItemsSource = loadOp.Entities;
    }
 }
#endregion //ResetButton_Click
 
#region UpdateButton_Click
//Submit changes
private void UpdateButton_Click(object sender, RoutedEventArgs e)
{
    this.employeeDomainDataSource.DomainContext.SubmitChanges();
}

#endregion //UpdateButton_Click

Run the application:

An application with buttons that calls added queries and edit mode support.

Search employees by address.

When XamGrid.EditingSettings.EditMode is set to Cell or Row it is possible to update the DomainContext. Calling the DomainContext.SubmitChanges() method updates database.