Displaying DrillDown Chart Using Hyperlink Column in Silverlight FlexGrid
This blog focuses on a small utility implementation where a drilled down C1Chart control is used to display detailed data for each row in C1FlexGrid. ComponentOne already provides a separate suite for Data Analysis in the form of OLAP for Silverlight. However, we may not need a full fledged control for small analytic display every time. In such a scenario, we can bind existing C1Chart control to the required data source to display the data.
Project Setup
We will begin this implementation by creating two demo DataTables. Since Silverlight does not provide DataTables or DataSets, we will use C1Data assembly which implements the standard DataSet, DataTable, and DataView classes similar to what we have in Winforms or ASP.Net. We create Two DataTables:
- Employee
- Sales
public DataTable ParentTable()
{
DataTable EmployeeTable = new DataTable();
EmployeeTable.Name = "Employee";
EmployeeTable.Columns.Add(new DataColumn("EmployeeID", typeof(Int32)));
EmployeeTable.Columns.Add(new DataColumn("EmployeeName", typeof(string)));
EmployeeTable.Columns.Add(new DataColumn("EmployeeCity", typeof(string)));
EmployeeTable.Columns.Add(new DataColumn("EmployeeDate", typeof(DateTime)));
DataRow dr = EmployeeTable.NewRow();
dr.ItemArray = new object[] { 231, "John", "London", DateTime.Now.AddDays(new Random().Next(0, 300)) };
EmployeeTable.Rows.Add(dr);
dr = EmployeeTable.NewRow();
dr.ItemArray = new object[] { 232, "James", "Berlin", DateTime.Now.AddDays(new Random().Next(0, 300)) };
EmployeeTable.Rows.Add(dr);
dr = EmployeeTable.NewRow();
dr.ItemArray = new object[] { 233, "Lina", "Washington D.C.", DateTime.Now.AddDays(new Random().Next(0, 300)) };
EmployeeTable.Rows.Add(dr);
dr = EmployeeTable.NewRow();
dr.ItemArray = new object[] { 234, "David", "London", DateTime.Now.AddDays(new Random().Next(0, 300)) };
EmployeeTable.Rows.Add(dr);
dr = EmployeeTable.NewRow();
dr.ItemArray = new object[] { 235, "Michael", "Moscow", DateTime.Now.AddDays(new Random().Next(0, 300)) };
EmployeeTable.Rows.Add(dr);
return EmployeeTable;
}
public DataTable ChildTable()
{
DataTable SalesTable = new DataTable();
SalesTable.Name = "Sales";
SalesTable.Columns.Add(new DataColumn("EmployeeID", typeof(Int32)));
SalesTable.Columns.Add(new DataColumn("Region", typeof(string)));
SalesTable.Columns.Add(new DataColumn("SalesAmount", typeof(Int32)));
DataRow dr = SalesTable.NewRow();
dr.ItemArray = new object[] { 231, "North", 100000 };
SalesTable.Rows.Add(dr);
dr = SalesTable.NewRow();
dr.ItemArray = new object[] { 231, "East", 150000 };
SalesTable.Rows.Add(dr);
dr = SalesTable.NewRow();
dr.ItemArray = new object[] { 231, "West", 165000 };
SalesTable.Rows.Add(dr);
dr = SalesTable.NewRow();
dr.ItemArray = new object[] { 231, "South", 200000 };
SalesTable.Rows.Add(dr);
dr = SalesTable.NewRow();
dr.ItemArray = new object[] { 232, "North", 200000 };
SalesTable.Rows.Add(dr);
dr = SalesTable.NewRow();
dr.ItemArray = new object[] { 232, "East", 175000 };
SalesTable.Rows.Add(dr);
dr = SalesTable.NewRow();
dr.ItemArray = new object[] { 232, "West", 155000 };
SalesTable.Rows.Add(dr);
dr = SalesTable.NewRow();
dr.ItemArray = new object[] { 232, "South", 200000 };
SalesTable.Rows.Add(dr);
dr = SalesTable.NewRow();
dr.ItemArray = new object[] { 233, "North", 200000 };
SalesTable.Rows.Add(dr);
dr = SalesTable.NewRow();
dr.ItemArray = new object[] { 233, "East", 185000 };
SalesTable.Rows.Add(dr);
dr = SalesTable.NewRow();
dr.ItemArray = new object[] { 233, "West", 165000 };
SalesTable.Rows.Add(dr);
dr = SalesTable.NewRow();
dr.ItemArray = new object[] { 233, "South", 150000 };
SalesTable.Rows.Add(dr);
dr = SalesTable.NewRow();
dr.ItemArray = new object[] { 234, "North", 250000 };
SalesTable.Rows.Add(dr);
dr = SalesTable.NewRow();
dr.ItemArray = new object[] { 234, "East", 150000 };
SalesTable.Rows.Add(dr);
dr = SalesTable.NewRow();
dr.ItemArray = new object[] { 234, "West", 195000 };
SalesTable.Rows.Add(dr);
dr = SalesTable.NewRow();
dr.ItemArray = new object[] { 234, "South", 200000 };
SalesTable.Rows.Add(dr);
return SalesTable;
}
The next step is to define the columns in C1FlexGrid control and make the required XAML settings for binding the datasource.
<c1:C1FlexGrid c1:LicenseMode.Evaluation="True" Name="c1FlexGrid1" AutoGenerateColumns="False">
<c1:C1FlexGrid.Columns>
<c1:Column Header="ID" Binding="{Binding EmployeeID}" HeaderHorizontalAlignment="Center" HorizontalAlignment="Center"/>
<c1:Column Header="Name" Binding="{Binding EmployeeName}" HeaderHorizontalAlignment="Center"/>
<c1:Column Header="City" Binding="{Binding EmployeeCity}" HeaderHorizontalAlignment="Center"/>
<c1:Column Header="Date" Binding="{Binding EmployeeDate,StringFormat=MM/dd/yyyy}" HeaderHorizontalAlignment="Center"/>
<c1:Column Header="Sales Details" HeaderHorizontalAlignment="Center">
<c1:Column.CellTemplate>
<DataTemplate>
<HyperlinkButton ClickMode="Press" Click="HyperlinkButton_Click" Content="Click" HorizontalContentAlignment="Center" />
</DataTemplate>
</c1:Column.CellTemplate>
</c1:Column>
</c1:C1FlexGrid.Columns>
</c1:C1FlexGrid>
The above code has a Hyperlink column which will be used to display the detailed Chart in a separate C1Window container.
DrillDown Charts Implementation
Lets have a look at the code implementation on Hyperlink cell click event.
private void HyperlinkButton_Click(object sender, RoutedEventArgs e)
{
int rowIndex = Grid.GetRow((e.OriginalSource as HyperlinkButton).Parent as Border);
int CustId = (int)(c1FlexGrid1.Rows[rowIndex].DataItem as DataRowView).GetData("EmployeeID");
ShowChart(CustId);
}
When we click on the Hyperlink cell, we have to retrieve the Employee ID for which the detailed data would be displayed. Once we have the ID, we will bind the chart to filtered rows. ShowChart() module is used to create the Chart display.
public void ShowChart(int empID)
{
C1Window wnd = new C1Window();
wnd.Header = "Sales Report";
wnd.Height = 300;
wnd.Width = 300;
C1.Silverlight.Chart.C1Chart _c1Chart = new C1.Silverlight.Chart.C1Chart();
wnd.Content = _c1Chart;
// Clear current chart
_c1Chart.Reset(true);
// Set chart type
_c1Chart.ChartType = C1.Silverlight.Chart.ChartType.Column;
// Get axes
Axis valueAxis = _c1Chart.View.AxisY;
Axis labelAxis = _c1Chart.View.AxisX;
// Configure label axis
labelAxis.Title = new TextBlock() { Text = "Region", FontSize = 14, FontWeight = FontWeights.Bold };
labelAxis.AutoMin = true;
labelAxis.AnnoAngle = 45;
// Configure value axis
valueAxis.Title = new TextBlock() { Text = " Sales Amount ($)", FontSize = 14, FontWeight = FontWeights.Bold };
valueAxis.AutoMin = false;</a>
valueAxis.Min = 0;
// Get the data
DataView dv = ChildTable().DefaultView;
dv.RowFilter = "EmployeeID = " + empID.ToString();
_c1Chart.Data.ItemsSource = dv;
// Show Product Name along x axis
_c1Chart.Data.ItemNameBinding = new Binding("Region");
// Add data series
var ds = new DataSeries();
ds.Label = "Unit Price";
ds.ValueBinding = new Binding("SalesAmount");
_c1Chart.Data.Children.Add(ds);
wnd.ShowModal();
wnd.CenterOnScreen();
}
So this is it. Once we have all the code included we can click on the HyperLink column cell to get the data displayed inside a chart. The only thing left is setting the ItemSource for C1FlexGrid control.
public MainPage()
{
InitializeComponent();
c1FlexGrid1.ItemsSource = ParentTable().DefaultView;
}
See the attached sample for complete implementation. Download Sample