HomeASP.NET Displaying Graphs with an Object Oriented ...
Displaying Graphs with an Object Oriented Approach using Silverlight SDK and Visual Studio 2008
In this article, we will focus on developing a Silverlight application which consumes an ASP.NET web service and presents data in the form of a bar graph using Visual Studio 2008. We will follow a simple object oriented approach for creating dynamic Silverlight objects using Silverlight SDK.
If you are new to developing Silverlight applications, I strongly suggest you to go through my first walkthrough article in this series.
The entire source code for this article is available in the form of a downloadable zip file. The solution was developed using Microsoft Visual Studio 2008 Beta 2 and Microsoft Silverlight 1.1 Alpha on Microsoft Windows Server 2003 Enterprise Edition with Microsoft SQL Server 2005 Enterprise Edition. I didn’t really test it in any other environment. I request that you post in the discussion area if you have any problems with execution.
Understanding the Visual Studio solution
Once you download the source code, you will find a folder named “SilverlightSampleWithWebService.” This contains a Visual Studio 2008 solution with three projects.
NorthwindService
SilverlightTest
SilverlightTest2
First of all, the above projects must be configured on same web server (IIS) you will use for testing the solution. Make sure that all of the above web sites are configured with ASP.NET 2.0 runtime (in IIS). Do not forget to provide security to the web site and folders. All of these steps are explained in greater detail in my previous article.
Once you open the above Visual Studio 2008 solution, the solution explorer looks like the following screen shot:
“NorthwindService” is an ASP.NET web service which provides information (data) to consumers by accessing data from the database. “SilverlightTest” simply displays a particular product and its sale value along with a representation of a graph (comparing all product sales). “SilverlightTest2” further extends “SilverlightTest” with an object oriented approach for presenting multiple rows of data along with the graph representation.
To hold multiple rows from the “Products” table, a new collection class named “Products.vb” is developed (using generics) as follows:
Imports System.Collections.Generic
Public Class Products
Inherits List(Of Product)
End Class
Finally, the web service contains only three methods as follows:
GetProductInfo
GetProductList
GetTotalSaleValue
“GetProductInfo” simply returns the information about a particular product. “GetProductList” returns a collection of “Product” objects (say, multiple product information). “GetTotalSaleValue” returns the sale value of all products in the Northwind database.
The entire source code for the web service is as follows:
Imports System.Web.Services
Imports System.Web.Services.Protocols
Imports System.ComponentModel
Imports System.Data.SqlClient
' To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line.
Public Function GetProductInfo(ByVal ProductID As Integer) As Product
Using cn As New SqlConnection(ConfigurationManager.ConnectionStrings ("cnNorthwind").ConnectionString)
Using cmd As New SqlCommand("SELECT ProductID, ProductName, UnitPrice, UnitsInStock, UnitsOnOrder,(SELECT sum(UnitPrice * Quantity) FROM dbo. [Order Details] WHERE ProductID = a.ProductID) as SaleValue FROM dbo.Products as a WHERE ProductID=" & ProductID, cn)
Using cn As New SqlConnection(ConfigurationManager.ConnectionStrings ("cnNorthwind").ConnectionString)
Using cmd As New SqlCommand("SELECT ProductID, ProductName, UnitPrice, UnitsInStock, UnitsOnOrder,(SELECT sum(UnitPrice * Quantity) FROM dbo. [Order Details] WHERE ProductID = a.ProductID) as SaleValue FROM dbo.Products as a ORDER BY 6 DESC", cn)
This is available in the “SilverlightTest” project. A web reference to “NorthwindService” is added to this. It simply displays the information (dynamically) as shown below:
Product Name (TextBlock)
Sale Value (TextBlock)
Graph Outline (Rectangle with White fill)
Graph Fill (Rectangle with Brown fill)
Percentage of Sale Value (TextBlock)
The following is the code for adding the objects to the Silverlight canvas:
Partial Public Class Page
Inherits Canvas
Public Sub Page_Loaded(ByVal o As Object, ByVal e As EventArgs)
' Required to initialize variables
InitializeComponent()
Dim svcNorthwind As New NorthwindService.ProductService
Dim objProject As NorthwindService.Product = svcNorthwind.GetProductInfo(38)
Dim TotalSaleValue As Double = svcNorthwind.GetTotalSaleValue
Dim ProductSalePercentage As Double = Math.Round((objProject.SaleTillToDate * 100) / (TotalSaleValue), 2)
'adding textblock related to Product Name
Dim tbProductName As New TextBlock
With tbProductName
.Text = objProject.ProductName
.Width = 172
.Height = 16
.FontSize = 12
.TextWrapping = TextWrapping.Wrap
.SetValue(Canvas.LeftProperty, 8)
.SetValue(Canvas.TopProperty, 8)
End With
Me.Children.Add(tbProductName)
'adding textblock related to Sale value
Dim tbSaleValue As New TextBlock
With tbSaleValue
.Text = objProject.SaleTillToDate
.Width = 140
.Height = 16
.FontSize = 12
.TextWrapping = TextWrapping.Wrap
.SetValue(Canvas.LeftProperty, 195)
.SetValue(Canvas.TopProperty, 8)
End With
Me.Children.Add(tbSaleValue)
'adding rectangle related to graph outline
Dim rGraphOutline As New Rectangle
With rGraphOutline
.Width = 222
.Height = 16
.Fill = New SolidColorBrush(Colors.White)
.Stroke = New SolidColorBrush(Colors.Black)
.SetValue(Canvas.LeftProperty, 351)
.SetValue(Canvas.TopProperty, 8)
End With
Me.Children.Add(rGraphOutline)
'adding rectangle related to graph fill
Dim rGraphFill As New Rectangle
With rGraphFill
.Width = (222 * ProductSalePercentage) / 100
.Height = 16
.Fill = New SolidColorBrush(Colors.Brown)
.Stroke = New SolidColorBrush(Colors.Black)
.SetValue(Canvas.LeftProperty, 351)
.SetValue(Canvas.TopProperty, 8)
End With
Me.Children.Add(rGraphFill)
'adding textblock related to Percentage
Dim tbPercentage As New TextBlock
With tbPercentage
.Text = ProductSalePercentage & "%"
.Width = 64
.Height = 16
.FontSize = 12
.TextWrapping = TextWrapping.Wrap
.SetValue(Canvas.LeftProperty, 577)
.SetValue(Canvas.TopProperty, 8)
End With
Me.Children.Add(tbPercentage)
End Sub
End Class
Hit F5 to execute the application and point your URL to
http://localhost/SilverlightTest/TestPage.html
Pointing to the URL manually as above (in the browser) is essential, because the request to the web service must be from the same web server as that of Silverlight project. Otherwise, it may raise issues related to “cross domain access.”
Even though you are pointing manually to the localhost, the Silverlight project can still be debugged in the same traditional manner. The URL must be pointed to in the browser window which came up when F5 is hit (otherwise, you will have to attach the process for debugging).
If everything went well, you should see the output as follows:
As I would like to implement a simple object oriented approach to displaying multiple rows, I added a new class named “ProductUIFactory” to the “SilverlightTest2” project. This is the main class which generated all blocks of Silverlight objects dynamically for each row of Products. It is defined as follows:
Public Class ProductUIFactory
Inherits NorthwindService.Product
Dim _CanvasTop As Double = 0
Dim _TotalSaleValue As Double = 0
Public Sub New(ByVal obj As NorthwindService.Product)
Me.ProductID = obj.ProductID
Me.ProductName = obj.ProductName
Me.SaleTillToDate = obj.SaleTillToDate
Me.UnitPrice = obj.UnitPrice
Me.UnitsInStock = obj.UnitsInStock
Me.UnitsOnOrder = obj.UnitsOnOrder
End Sub
Public Property CurrentCanvasTop() As Double
Get
Return _CanvasTop
End Get
Set(ByVal value As Double)
_CanvasTop = value
End Set
End Property
Public Property TotalSaleValue() As Double
Get
Return _TotalSaleValue
End Get
Set(ByVal value As Double)
_TotalSaleValue = value
End Set
End Property
Public ReadOnly Property ProductSalePercentage() As Double
Public ReadOnly Property UIProductName() As TextBlock
Get
'adding textblock related to Product Name
Dim tbProductName As New TextBlock
With tbProductName
.Text = Me.ProductName
.Width = 172
.Height = 16
.FontSize = 12
'.TextWrapping = TextWrapping.Wra
.SetValue(Canvas.LeftProperty, 8)
.SetValue(Canvas.TopProperty, CurrentCanvasTop)
End With
Return tbProductName
End Get
End Property
Public ReadOnly Property UISaleValue() As TextBlock
Get
'adding textblock related to Sale value
Dim tbSaleValue As New TextBlock
With tbSaleValue
.Text = Me.SaleTillToDate
.Width = 140
.Height = 16
.FontSize = 12
.TextWrapping = TextWrapping.Wrap
.SetValue(Canvas.LeftProperty, 195)
.SetValue(Canvas.TopProperty, CurrentCanvasTop)
End With
Return tbSaleValue
End Get
End Property
Public ReadOnly Property UIGraphOutline() As Rectangle
Get
'adding rectangle related to graph outline
Dim rGraphOutline As New Rectangle
With rGraphOutline
.Width = 222
.Height = 16
.Fill = New SolidColorBrush(Colors.White)
.Stroke = New SolidColorBrush(Colors.Black)
.SetValue(Canvas.LeftProperty, 351)
.SetValue(Canvas.TopProperty, CurrentCanvasTop)
End With
Return rGraphOutline
End Get
End Property
Public ReadOnly Property UIGraphFill() As Rectangle
Get
Dim rGraphFill As New Rectangle
With rGraphFill
.Width = (222 * Me.ProductSalePercentage) / 100
.Height = 16
.Fill = New SolidColorBrush(Colors.Brown)
.Stroke = New SolidColorBrush(Colors.Black)
.SetValue(Canvas.LeftProperty, 351)
.SetValue(Canvas.TopProperty, CurrentCanvasTop)
End With
Return rGraphFill
End Get
End Property
Public ReadOnly Property UIPercentage() As TextBlock
Get
'adding textblock related to Percentage
Dim tbPercentage As New TextBlock
With tbPercentage
.Text = Me.ProductSalePercentage & "%"
.Width = 64
.Height = 16
.FontSize = 12
.TextWrapping = TextWrapping.Wrap
.SetValue(Canvas.LeftProperty, 577)
.SetValue(Canvas.TopProperty, CurrentCanvasTop)
End With
Return tbPercentage
End Get
End Property
#End Region
End Class
The code behind utilizing the above class is developed as follows:
Imports System.Collections.Generic
Partial Public Class Page
Inherits Canvas
Public Sub Page_Loaded(ByVal o As Object, ByVal e As EventArgs)
' Required to initialize variables
InitializeComponent()
Dim svcNorthwind As New NorthwindService.ProductService
Dim objProducts As NorthwindService.Product() = svcNorthwind.GetProductList
Dim TotalSaleValue As Double = svcNorthwind.GetTotalSaleValue
Dim i As Integer = 0
For Each objProduct As NorthwindService.Product In objProducts
Dim objFactory As New ProductUIFactory(objProduct)
With objFactory
.CurrentCanvasTop = (20 * i)
.TotalSaleValue = TotalSaleValue
Me.Children.Add(.UIProductName)
Me.Children.Add(.UISaleValue)
Me.Children.Add(.UIGraphOutline)
Me.Children.Add(.UIGraphFill)
Me.Children.Add(.UIPercentage)
End With
i += 1
Next
End Sub
End Class
You can observe that for each product, we are generating a new row of Silverlight objects using the “ProductUIFactory” class developed in the previous section.
The following is the output you can expect for the above:
I hope you enjoyed the article and any suggestions, bugs, errors, enhancements etc. are highly appreciated at http://jagchat.spaces.live.com