Using the Infragistics XamGrid and XamDataChart with Hierarchical Data and WCF RIA Services – Part 2

[Infragistics] Mihail Mateev / Sunday, June 20, 2010

This Article describes how to use the Infragistics XamGrid and the new XamDataChart with WCF RIA Services.

Important things, related with WCF RIA Services and  the Infragistics XamGrid and RIA Services are described in the article "Using the Infragistics XamGrid with RIA Services" and the part 1 of this article.

To create an application you need to repeat first six steps from the previous article: "Using the Infragistics XamGrid with RIA Services":

Creating of a demo application includes the steps, mentioned in previous two articles"

Create a RIA Services enabled Silverlight 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

Steps are described in the "Using the Infragistics XamGrid with RIA Services" article

Use a hierarchical data with the Infragistics XamGrid:

  1. Modify our Domain Service class NorthWindDomainService - add query GetCustomersWithOrders that returns data from table Customers with data from child table Orders.
  2. Add data from Customers table via Data Sources window, represented via XamGrid.
  3. Create a summary field Freight in the Customer class modifying NorthWindModel and NorthWindDomainService classes:

 Steps are described in the part 1 of this article.

Requirements:

 

You need to install trial version of NetAdvantage for Silverlight Line of Business 10.2 and NetAdvantage for Silverlight Data Visualization 10.2.

In the part 2 of this article will be demonstrated the new Infragistics XamDataChart , used with WCF RIA Services.

Add XamDataChart to the Silverlight application:

To use XamDataChart you need:

  •  Add XamDataChart from toolbox (it will automatically reference InfragisticsSL4.Controls.Charts.XamDataChart.v10.2.dll and InfragisticsSL4.DataVisualization.v10.2.dll libraries).

 

<ig:XamDataChart Grid.Column="1" Margin="20" Name="xamDataChart" VerticalAlignment="Top" />
  • Add as Data Context Data from the created cutomerDomainDataSource.
  • Add axes:

 CategoryXAxis, named mxXAxis and  binded with the CustomerID property from the Customers data source .

NumericYAxis, named xamYAxisFreight and used to visualize the Freight for each Customer.

  • Add Series, Binded to the DataContext and using created CategoryXAxis and NumericYAxis.

 

There is full XAML code:

 <ig:XamDataChart Grid.Column="1" Margin="20"  x:Name="xamDataChart" DataContext="{Binding ElementName=customerDomainDataSource, Path=Data}"

                PanModifier="Shift"
                DefaultInteraction="DragZoom"
                HorizontalZoomable="True"
                HorizontalZoombarVisibility="Visible"
                VerticalZoomable="True"
<ig:XamDataChart.Axes>
    <ig:CategoryXAxis x:Name="xmXAxis" ItemsSource="{Binding}" Label="{}{CustomerID}"  />
    <ig:NumericYAxis x:Name="xmYAxisFreight" />
</ig:XamDataChart.Axes>
 
<ig:XamDataChart.Series>
    <ig:ColumnSeries Thickness="2"                                                  
                                        ItemsSource="{Binding}"
                                        ValueMemberPath="Freight"
                                        XAxis="{Binding ElementName=xmXAxis}"
                                        YAxis="{Binding ElementName=xmYAxisFreight}">
    </ig:ColumnSeries>
</ig:XamDataChart.Series>
</ig:XamDataChart>

When run the application we will have both XamGrid and XamDataChart , used the same data source:

 

XamDataChart interactions:
Let’s make the chart interactive:
When click over a column from the XamDataChart series, column will be filled with different color and there will be filtering applied to XamGrid.
There will be added two check boxes, that will define to filter values , greater or lower than the value of the selected series column. A Button “Reset Limits” will remove the filter.

 <StackPanel>

    <CheckBox x:Name="ChkLowerFilter" Content="Lower Limits" />
    <CheckBox x:Name="ChkUpperFilter" Content="Upper Limits" />
    <Button x:Name="BtnReset" Content="Reset Limits" Click="BtnReset_Click"/>
</StackPanel>

In the ctor there are added event handlers for SeriesMouseLeftButtonDown and XamDataChartSeriesMouseLeftButtonDown events.

public MainPage()
{
    InitializeComponent();
    this.xamDataChart.SeriesMouseLeftButtonDown += new Infragistics.Controls.Charts.DataChartMouseButtonEventHandler(XamDataChartSeriesMouseLeftButtonDown);
    this.xamDataChart.SeriesMouseLeftButtonUp += new Infragistics.Controls.Charts.DataChartMouseButtonEventHandler(XamDataChartSeriesMouseLeftButtonUp);
}
 
void XamDataChartSeriesMouseLeftButtonDown(object sender, Infragistics.Controls.Charts.DataChartMouseButtonEventArgs e)
{
//Get the selected Item as Customer
    Customer customer = e.Item as Customer;
    if (customer == null)
    {
        return;
    } 
    string value = customer.CustomerID;
 
    Shape x = e.OriginalSource as Shape;
    if (x != null)
    {
        _origBrush = x.Fill;
        _isChanged = true;
        x.Fill = new SolidColorBrush(Colors.Cyan);
    }
 
//Applying the filter
    Column col = customerXamGrid.Columns.DataColumns["CustomerID"];
    RowsFilter rf = new RowsFilter(typeof(string), col);
 
    if (ChkLowerFilter.IsChecked == true)
    {
        rf.Conditions.Add(new ComparisonCondition() { Operator = ComparisonOperator.GreaterThan, FilterValue = value});
    }
    else if (ChkUpperFilter.IsChecked == true)
    {
        rf.Conditions.Add(new ComparisonCondition() { Operator = ComparisonOperator.LessThan, FilterValue = value });
    }
    else
    {
        return;
    } 
    customerXamGrid.FilteringSettings.RowFiltersCollection.Add(rf);
}
 
void XamDataChartSeriesMouseLeftButtonUp(object sender, Infragistics.Controls.Charts.DataChartMouseButtonEventArgs e)
{
    if (_isChanged)
    {
//Restore the color
        Shape x = e.OriginalSource as Shape;
        if (x != null)
        {
            x.Fill = _origBrush;
        }
    }
}
 
//remove the filter
private void BtnReset_Click(object sender, RoutedEventArgs e)
{
    this.customerXamGrid.FilteringSettings.RowFiltersCollection.Clear();
}

 

Filter the values greater than selected value. 

Filter the values, less than selected value.

Add a XamDataChart with details:

Create a chart with details - freights by date for the selected Customer object:

  • To be possible to get all orders for a specific Customer add in the NorthWindDomainService class method GetOrdersByCustomerId:

public IQueryable<Order> GetOrdersByCustomerId(string customerId)

{
    return this.ObjectContext.Orders.Where(c => c.CustomerID == customerId);
}

Add a CheckBox control to maintain when the detail chart will be displayed.

<CheckBox x:Name="ChkShowDetails" Content="Show Details" />
  • Add an InfragisticsSL4.Controls.Interactions.XamDialogWindow.v10.2.dll reference
  • Add in XAML a XamDialogWindow with XamDataChart inside it. Chart will show the Freight by OrderDate value for a selected Customer.
<ig:XamDialogWindow Grid.ColumnSpan="2" x:Name="xamChartWindow" Header="Customer Orders" WindowState="Hidden"
        RestrictInContainer="False" StartupPosition="Center" Width="450" Height="250">
    <ig:XamDataChart Margin="20" x:Name="xamOrderDataChart"
                    PanModifier="Shift"
                    DefaultInteraction="DragZoom"
                    HorizontalZoomable="True"
                    HorizontalZoombarVisibility="Visible"
                    VerticalZoomable="True"
                    VerticalZoombarVisibility="Visible" >
    <ig:XamDataChart.Axes>
        <ig:CategoryXAxis x:Name="xmXAxis2" ItemsSource="{Binding}" Label="{}{OrderDate:MM/dd/yyyy}"  />
        <ig:NumericYAxis x:Name="xmYAxisFreight2" />
    </ig:XamDataChart.Axes>
 
    <ig:XamDataChart.Series>
        <ig:ColumnSeries Thickness="2"                                                  
                                            ItemsSource="{Binding}"
                                            ValueMemberPath="Freight"
                                            XAxis="{Binding ElementName=xmXAxis2}"
                                            YAxis="{Binding ElementName=xmYAxisFreight2}">
        </ig:ColumnSeries>
    </ig:XamDataChart.Series>
</ig:XamDataChart>

</ig:XamDialogWindow>

  • Add an Event Handler to XamGrid.SelectedRowsCollectionChanged event in the ctor:

 

this.customerXamGrid.SelectedRowsCollectionChanged += new EventHandler<SelectionCollectionChangedEventArgs<SelectedRowsCollection>>(CustomerXamGrid_SelectedRowsCollectionChanged);
void CustomerXamGrid_SelectedRowsCollectionChanged(object sender, SelectionCollectionChangedEventArgs<SelectedRowsCollection> e)
{
    if (this.ChkShowDetails.IsChecked != true || e.NewSelectedItems.Count == 0)
    {
        return;
    }
    Row selelctedRow = e.NewSelectedItems[0];
    string customerId = selelctedRow.Cells["CustomerID"].Value.ToString();
    NorthWindDomainContext context = this.customerDomainDataSource.DomainContext as NorthWindDomainContext;
    if (context != null)
    {
        LoadOperation<Order> loadOp = context.Load(context.GetOrdersByCustomerIdQuery(customerId));
        this.xamOrderDataChart.DataContext = loadOp.Entities;
        this.xamChartWindow.Show();
    }
}

 

 

Add detailed information to UI:

To detailed info for the selected customer :

  • Add a details form from Data Sources window for the Order and drag it to Silverlight application MainPage.xaml in design mode.
  • Select GetCustomersByCustomerIdQuery as query that is used to generate the data:

 

 

 

It will add a Gird with controls , displaying a detail information for the selected Customer:

  • Remove code that Executes query to fill the detail data:
<StackPanel Height="30" HorizontalAlignment="Left" Orientation="Horizontal" VerticalAlignment="Top">
    <sdk:Label Content="Customer Id:" Margin="3" VerticalAlignment="Center" />
    <TextBox Name="customerIdTextBox" Width="60" />
    <Button Command="{Binding Path=LoadCommand, ElementName=orderDomainDataSource}" Content="Load" Margin="3" Name="orderDomainDataSourceLoadButton" />
</StackPanel>
  • Keep other XAML code:
<riaControls:DomainDataSource AutoLoad="False" d:DesignData="{d:DesignInstance my:Customer, CreateList=true}" Height="0" LoadedData="CustomerDomainDataSource1_LoadedData" Name="customerDomainDataSource1" QueryName="GetCustomerByIdQuery" Width="0">
    <riaControls:DomainDataSource.DomainContext>
        <my:NorthWindDomainContext />
    </riaControls:DomainDataSource.DomainContext>
    <riaControls:DomainDataSource.QueryParameters>
        <riaControls:Parameter ParameterName="customerId" Value="{Binding ElementName=customerIdTextBox, Path=Text}" />
    </riaControls:DomainDataSource.QueryParameters>
</riaControls:DomainDataSource>
 
<Grid DataContext="{Binding ElementName=customerDomainDataSource1, Path=Data}" Grid.Row="1" HorizontalAlignment="Left" Margin="3" Name="grid1" VerticalAlignment="Top">
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="Auto" />
        <ColumnDefinition Width="Auto" />
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto" />
        <RowDefinition Height="Auto" />
        <RowDefinition Height="Auto" />
        <RowDefinition Height="Auto" />
        <RowDefinition Height="Auto" />
        <RowDefinition Height="Auto" />
        <RowDefinition Height="Auto" />
        <RowDefinition Height="Auto" />
        <RowDefinition Height="Auto" />
        <RowDefinition Height="Auto" />
        <RowDefinition Height="Auto" />
        <RowDefinition Height="Auto" />
    </Grid.RowDefinitions>
    <sdk:Label Content="Address:" Grid.Column="0" Grid.Row="0" HorizontalAlignment="Left" Margin="3" VerticalAlignment="Center" />
    <TextBox Grid.Column="1" Grid.Row="0" Height="23" HorizontalAlignment="Left" Margin="3" Name="addressTextBox" Text="{Binding Path=Address, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true, TargetNullValue=''}" VerticalAlignment="Center" Width="120" />
    <sdk:Label Content="City:" Grid.Column="0" Grid.Row="1" HorizontalAlignment="Left" Margin="3" VerticalAlignment="Center" />
    <TextBox Grid.Column="1" Grid.Row="1" Height="23" HorizontalAlignment="Left" Margin="3" Name="cityTextBox" Text="{Binding Path=City, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true, TargetNullValue=''}" VerticalAlignment="Center" Width="120" />
    <sdk:Label Content="Company Name:" Grid.Column="0" Grid.Row="2" HorizontalAlignment="Left" Margin="3" VerticalAlignment="Center" />
    <TextBox Grid.Column="1" Grid.Row="2" Height="23" HorizontalAlignment="Left" Margin="3" Name="companyNameTextBox" Text="{Binding Path=CompanyName, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true, TargetNullValue=''}" VerticalAlignment="Center" Width="120" />
    <sdk:Label Content="Contact Name:" Grid.Column="0" Grid.Row="3" HorizontalAlignment="Left" Margin="3" VerticalAlignment="Center" />
    <TextBox Grid.Column="1" Grid.Row="3" Height="23" HorizontalAlignment="Left" Margin="3" Name="contactNameTextBox" Text="{Binding Path=ContactName, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true, TargetNullValue=''}" VerticalAlignment="Center" Width="120" />
    <sdk:Label Content="Contact Title:" Grid.Column="0" Grid.Row="4" HorizontalAlignment="Left" Margin="3" VerticalAlignment="Center" />
    <TextBox Grid.Column="1" Grid.Row="4" Height="23" HorizontalAlignment="Left" Margin="3" Name="contactTitleTextBox" Text="{Binding Path=ContactTitle, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true, TargetNullValue=''}" VerticalAlignment="Center" Width="120" />
    <sdk:Label Content="Country:" Grid.Column="0" Grid.Row="5" HorizontalAlignment="Left" Margin="3" VerticalAlignment="Center" />
    <TextBox Grid.Column="1" Grid.Row="5" Height="23" HorizontalAlignment="Left" Margin="3" Name="countryTextBox" Text="{Binding Path=Country, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true, TargetNullValue=''}" VerticalAlignment="Center" Width="120" />
    <sdk:Label Content="Customer ID:" Grid.Column="0" Grid.Row="6" HorizontalAlignment="Left" Margin="3" VerticalAlignment="Center" />
    <TextBox Grid.Column="1" Grid.Row="6" Height="23" HorizontalAlignment="Left" Margin="3" Name="customerIDTextBox1" Text="{Binding Path=CustomerID, Mode=OneWay}" VerticalAlignment="Center" Width="120" />
    <sdk:Label Content="Fax:" Grid.Column="0" Grid.Row="7" HorizontalAlignment="Left" Margin="3" VerticalAlignment="Center" />
    <TextBox Grid.Column="1" Grid.Row="7" Height="23" HorizontalAlignment="Left" Margin="3" Name="faxTextBox" Text="{Binding Path=Fax, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true, TargetNullValue=''}" VerticalAlignment="Center" Width="120" />
    <sdk:Label Content="Freight:" Grid.Column="0" Grid.Row="8" HorizontalAlignment="Left" Margin="3" VerticalAlignment="Center" />
    <TextBox Grid.Column="1" Grid.Row="8" Height="23" HorizontalAlignment="Left" Margin="3" Name="freightTextBox" Text="{Binding Path=Freight, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}" VerticalAlignment="Center" Width="120" />
    <sdk:Label Content="Phone:" Grid.Column="0" Grid.Row="9" HorizontalAlignment="Left" Margin="3" VerticalAlignment="Center" />
    <TextBox Grid.Column="1" Grid.Row="9" Height="23" HorizontalAlignment="Left" Margin="3" Name="phoneTextBox" Text="{Binding Path=Phone, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true, TargetNullValue=''}" VerticalAlignment="Center" Width="120" />
    <sdk:Label Content="Postal Code:" Grid.Column="0" Grid.Row="10" HorizontalAlignment="Left" Margin="3" VerticalAlignment="Center" />
    <TextBox Grid.Column="1" Grid.Row="10" Height="23" HorizontalAlignment="Left" Margin="3" Name="postalCodeTextBox" Text="{Binding Path=PostalCode, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true, TargetNullValue=''}" VerticalAlignment="Center" Width="120" />
    <sdk:Label Content="Region:" Grid.Column="0" Grid.Row="11" HorizontalAlignment="Left" Margin="3" VerticalAlignment="Center" />
    <TextBox Grid.Column="1" Grid.Row="11" Height="23" HorizontalAlignment="Left" Margin="3" Name="regionTextBox" Text="{Binding Path=Region, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true, TargetNullValue=''}" VerticalAlignment="Center" Width="120" />

</Grid>

 Modify the SelectedRowsCollectionChanged event handler to reload the details data:

void CustomerXamGrid_SelectedRowsCollectionChanged(object sender, SelectionCollectionChangedEventArgs<SelectedRowsCollection> e)
{
    if (this.ChkShowDetails.IsChecked != true || e.NewSelectedItems.Count == 0)
    {
        return;
    }
 
    Row selelctedRow = e.NewSelectedItems[0];
 
    string customerId = selelctedRow.Cells["CustomerID"].Value.ToString();
 
    NorthWindDomainContext context = this.customerDomainDataSource.DomainContext as NorthWindDomainContext;
    if (context != null)
    {
        LoadOperation<Order> loadOp = context.Load(context.GetOrdersByCustomerIdQuery(customerId));
        this.xamOrderDataChart.DataContext = loadOp.Entities;
        this.xamChartWindow.Show();
 
       //Reload Details Data
        customerDomainDataSource1.QueryParameters.Clear();
        customerDomainDataSource1.QueryParameters.Add(new Parameter { ParameterName = "customerId", Value = customerId });
        customerDomainDataSource1.Load();
 
    }
 
}

Start the application:

Detailed data shows attribute information for the selected customer.