ARTICLE

Stock Tracker Custom Control

Posted by Scott Lysle Articles | ASP.NET using VB.NET November 03, 2006
This article describes the construction of a custom control used to check stock prices as made available through a public web service. The article includes the source code for this custom control and well as a demonstration site used to test the control.
Download Files:
 
Reader Level:

Introduction:

This article describes the construction of a custom control used to check stock prices as made available through a public web service. The article includes the source code for this custom control and well as a demonstration site used to test the control.

Figure 1:  Stock Tracker Custom Controls in Use

Getting Started:

The files included with this project include a web control library project and a demonstration web site. In order to get started, open the included zip file and install the two projects onto your file system. Open IIS and create a virtual directory for the web application. Open the solution into Visual 2005 and make any changes necessary to bring both projects into the solution. Once properly configured, your solution explorer should show these projects, references, and files:

Figure 2:  Solution Explorer with Web App and Control Library

In examining the solution, note that the "StockTracker" control library contains only a single control and that control is called "StockDog". This project also includes a web reference that points to the http://www.webservicex.net site; this public site supports the web service used to capture the stock prices.

The web application contains only a single web page (default.aspx) and includes a reference to the "StockTracker" DLL.
The web application serves as a container used to test the custom control; the default.aspx page contains three separate instances of the custom control. Each of these three instances is directed to retrieve stock information from three separate stocks.

The Code:  StockDog

The "StockDog" custom control is constructed to retrieve the information from the web service upon initialization and to use that information to populate a collection of local member variables; each of the local member variables is set to contain one of the values collected from the web service.

The web service returns the requested data in the form of an XML string; this string is parsed to obtain the individual values used to populate the member variables. These member variables are in turn used to display the stock information when the page is rendered.

In examining the code, note that, aside from the default imports, only the System.XML class has been added. The class itself inherits from the WebControl class.

Imports System

Imports System.Collections.Generic

Imports System.ComponentModel

Imports System.Text

Imports System.Web

Imports System.Web.UI

Imports System.Web.UI.WebControls

Imports System.Xml 

 

<DefaultProperty("StockTicker"), ToolboxData("<{0}:StockDog runat=server></{0}:StockDog>")> _

Public Class StockDog

    Inherits WebControl

Following the class declaration, a region entitled "Declarations" is created and within that region are the declarations for all of the private member variables used within the control.

#Region "Declarations"

 

    Private mStocks As net.webservicex.www.StockQuote

    Private mXmlDoc As XmlDocument

    Private mStockTicker As String

    Private mLast As String

    Private mDate As String

    Private mTime As String

    Private mChange As String

    Private mOpen As String

    Private mHigh As String

    Private mLow As String

    Private mVolume As String

    Private mMktCap As String

    Private mPrevClose As String

    Private mPercentChng As String

    Private mAnnRange As String

    Private mEarns As String

    Private mPE As String

    Private mName As String 

#End Region

After the variable declarations, there is another region defined (Methods) and within that region is the code used to capture the data from the web service, and to read the XML string returned by that service and use the values to populate the member variables. The init handler calls a subroutine called "Fetch" each time the control is initialized.  Fetch accepts a single argument in the form of a string bearing the stock symbol (e.g., MSFT for Microsoft).

Inside Fetch, a new XML document is created.  The mStocks string variable is used to capture the XML string returned from the web service's GetQuote web method. GetQuote accepts the stock symbol as an argument. The returned string is loaded as XML into the XML document.

After the data is returned and placed inside the XML document, the next windy bit of code locates each specific node and captures the value associated with that node which is in turn used to populate the appropriate local member variable.

The code contained in the Methods region is as follows:

#Region "Methods"

 

    Private Sub StockDog_Init(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Init

 

        Fetch(StockTicker)

 

    End Sub 

 

    Public Sub Fetch(ByVal strStock As String)

 

        mXmlDoc = New XmlDocument()

        mStocks = New net.webservicex.www.StockQuote

        Dim strQuote As String = mStocks.GetQuote(strStock)

        mXmlDoc.LoadXml(strQuote)

 

        ' Set all of the private member variables to

        ' contain the values from the xml string returned

        ' from the web service

 

        ' Last

        Dim lastNodes As XmlNodeList

        Dim lastNode As XmlNode

        lastNodes = mXmlDoc.GetElementsByTagName("Last")

 

        For Each lastNode In lastNodes

            mLast = lastNode.ChildNodes(0).Value

        Next

 

        ' Date

        Dim dateNodes As XmlNodeList

        Dim dateNode As XmlNode

        dateNodes = mXmlDoc.GetElementsByTagName("Date")

 

        For Each dateNode In dateNodes

            mDate = dateNode.ChildNodes(0).Value

        Next

 

        ' Time

        Dim timeNodes As XmlNodeList

        Dim timeNode As XmlNode

        timeNodes = mXmlDoc.GetElementsByTagName("Time")

 

        For Each timeNode In timeNodes

            mTime = timeNode.ChildNodes(0).Value

        Next

 

        ' Change

        Dim changeNodes As XmlNodeList

        Dim changeNode As XmlNode

        changeNodes = mXmlDoc.GetElementsByTagName("Change")

 

        For Each changeNode In changeNodes

            mChange = changeNode.ChildNodes(0).Value

        Next

 

        ' Open

        Dim openNodes As XmlNodeList

        Dim openNode As XmlNode

        openNodes = mXmlDoc.GetElementsByTagName("Open")

 

        For Each openNode In openNodes

            mOpen = openNode.ChildNodes(0).Value

        Next

 

        ' High

        Dim highNodes As XmlNodeList

        Dim highNode As XmlNode

        highNodes = mXmlDoc.GetElementsByTagName("High")

 

        For Each highNode In highNodes

            mHigh = highNode.ChildNodes(0).Value

        Next

 

        ' Low

        Dim lowNodes As XmlNodeList

        Dim lowNode As XmlNode

        lowNodes = mXmlDoc.GetElementsByTagName("Low")

 

        For Each lowNode In lowNodes

            mLow = lowNode.ChildNodes(0).Value

        Next

 

        ' Volume

        Dim volumeNodes As XmlNodeList

        Dim volumeNode As XmlNode

        volumeNodes = mXmlDoc.GetElementsByTagName("Volume")

 

        For Each volumeNode In volumeNodes

            mVolume = volumeNode.ChildNodes(0).Value

        Next

 

        ' MrkCap

        Dim MrkCapNodes As XmlNodeList

        Dim MrkCapNode As XmlNode

        MrkCapNodes = mXmlDoc.GetElementsByTagName("MktCap")

 

        For Each MrkCapNode In MrkCapNodes

            mMktCap = MrkCapNode.ChildNodes(0).Value

        Next

 

        ' PrevClose

        Dim prevCloseNodes As XmlNodeList

        Dim prevCloseNode As XmlNode

        prevCloseNodes = mXmlDoc.GetElementsByTagName("PreviousClose")

 

        For Each prevCloseNode In prevCloseNodes

            mPrevClose = prevCloseNode.ChildNodes(0).Value

        Next

 

        ' mPercentChng

        Dim percentChngNodes As XmlNodeList

        Dim percentChngNode As XmlNode

        percentChngNodes = mXmlDoc.GetElementsByTagName("PercentageChange")

 

        For Each percentChngNode In percentChngNodes

            mPercentChng = percentChngNode.ChildNodes(0).Value

        Next

 

        ' mAnnRange

        Dim annRangeNodes As XmlNodeList

        Dim annRangeNode As XmlNode

        annRangeNodes = mXmlDoc.GetElementsByTagName("AnnRange")

 

        For Each annRangeNode In annRangeNodes

            mAnnRange = annRangeNode.ChildNodes(0).Value

        Next

 

        ' mEarns

        Dim earnsNodes As XmlNodeList

        Dim earnsNode As XmlNode

        earnsNodes = mXmlDoc.GetElementsByTagName("Earns")

 

        For Each earnsNode In earnsNodes

            mEarns = earnsNode.ChildNodes(0).Value

        Next

 

        ' mPE

        Dim PENodes As XmlNodeList

        Dim PENode As XmlNode

        PENodes = mXmlDoc.GetElementsByTagName("P-E")

 

        For Each PENode In PENodes

            mPE = PENode.ChildNodes(0).Value

        Next

 

        ' mName

        Dim nameNodes As XmlNodeList

        Dim nameNode As XmlNode

        nameNodes = mXmlDoc.GetElementsByTagName("Name")

 

        For Each nameNode In nameNodes

            mName = nameNode.ChildNodes(0).Value

        Next

 

    End Sub 

#End Region

The next region defined in the code is called "Properties"; as you likely guessed, this section contains the properties used by the control. In this case, aside from what was passed down through the inheritance of the WebControl class, the only property to define is a string value used to contain the stock symbol. The properties region and its single property are defined as follows:

#Region "Properties"

 

    <Category("Stock Symbol")> _

    <Browsable(True)> _

    <Description("Enter the stock ticker value.")> _

    Public Property StockTicker() As String

        Get

            Return mStockTicker

        End Get

        Set(ByVal value As String)

            mStockTicker = value

        End Set

    End Property

 

#End Region

The attributes of category, browsable, and description are used to provide design time support for the custom control. The category and description text will be displayed in the IDE's property editor whenever this control is selected by the developer using the control.

Having captured the values from the XML string returned from the web service, and having populated the local member variables using the values contained in the XML, the only remaining step is to render the control. A region entitled, "Rendering" follows and it contains the code necessary to render the control on the page.

The code used to render the control is pretty simple; the HtmlTextWriter is used to define a table  and set up its characteristics (cell padding and border in this example), each row of the table contains two cells, a label and its associated value are placed into each of those two cells. Once all of the data has been written into the table, the ending tag is rendered and the control is complete.

Naturally, you can change the configuration of the table or remove some of the data returned from the web service by making changes in the definition of the HTML as defined through the HtmlTextWriter. The RenderContents subroutine is overridden and the HTML is formatted within this subroutine through the use of the HtmlTextWriter. 

#Region "Rendering"

 

    Protected Overrides Sub RenderContents(ByVal output As HtmlTextWriter)

 

        output.AddAttribute(HtmlTextWriterAttribute.Cellpadding, "3")

        output.AddAttribute(HtmlTextWriterAttribute.Border, "1")

        output.RenderBeginTag(HtmlTextWriterTag.Table)

 

        output.RenderBeginTag(HtmlTextWriterTag.Tr)

 

        output.AddAttribute(HtmlTextWriterAttribute.Align, "left")

        output.RenderBeginTag(HtmlTextWriterTag.Td)

        output.Write("<b>Stock: </b>")

        output.RenderEndTag()

        output.RenderBeginTag(HtmlTextWriterTag.Td)

        output.Write(StockTicker)

        output.RenderEndTag()

 

        output.RenderEndTag()

        output.RenderBeginTag(HtmlTextWriterTag.Tr)

 

        output.AddAttribute(HtmlTextWriterAttribute.Align, "left")

        output.RenderBeginTag(HtmlTextWriterTag.Td)

        output.Write("<b>Company: </b>")

        output.RenderEndTag()

        output.RenderBeginTag(HtmlTextWriterTag.Td)

        output.Write(mName)

        output.RenderEndTag()

 

        output.RenderEndTag()

        output.RenderBeginTag(HtmlTextWriterTag.Tr)

 

        output.AddAttribute(HtmlTextWriterAttribute.Align, "left")

        output.RenderBeginTag(HtmlTextWriterTag.Td)

        output.Write("<b>Last: </b>")

        output.RenderEndTag()

        output.RenderBeginTag(HtmlTextWriterTag.Td)

        output.Write(mLast)

        output.RenderEndTag()

 

        output.RenderEndTag()

        output.RenderBeginTag(HtmlTextWriterTag.Tr)

 

        output.AddAttribute(HtmlTextWriterAttribute.Align, "left")

        output.RenderBeginTag(HtmlTextWriterTag.Td)

        output.Write("<b>Date: </b>")

        output.RenderEndTag()

        output.RenderBeginTag(HtmlTextWriterTag.Td)

        output.Write(mDate)

        output.RenderEndTag()

 

        output.RenderEndTag()

        output.RenderBeginTag(HtmlTextWriterTag.Tr)

 

        output.AddAttribute(HtmlTextWriterAttribute.Align, "left")

        output.RenderBeginTag(HtmlTextWriterTag.Td)

        output.Write("<b>Time: </b>")

        output.RenderEndTag()

        output.RenderBeginTag(HtmlTextWriterTag.Td)

        output.Write(mTime)

        output.RenderEndTag()

 

        output.RenderEndTag()

        output.RenderBeginTag(HtmlTextWriterTag.Tr)

 

        output.AddAttribute(HtmlTextWriterAttribute.Align, "left")

        output.RenderBeginTag(HtmlTextWriterTag.Td)

        output.Write("<b>Change: </b>")

        output.RenderEndTag()

        output.RenderBeginTag(HtmlTextWriterTag.Td)

        output.Write(mChange)

        output.RenderEndTag()

 

        output.RenderEndTag()

        output.RenderBeginTag(HtmlTextWriterTag.Tr)

 

        output.AddAttribute(HtmlTextWriterAttribute.Align, "left")

        output.RenderBeginTag(HtmlTextWriterTag.Td)

        output.Write("<b>Open: </b>")

        output.RenderEndTag()

        output.RenderBeginTag(HtmlTextWriterTag.Td)

        output.Write(mOpen)

        output.RenderEndTag()

 

        output.RenderEndTag()

        output.RenderBeginTag(HtmlTextWriterTag.Tr)

 

        output.AddAttribute(HtmlTextWriterAttribute.Align, "left")

        output.RenderBeginTag(HtmlTextWriterTag.Td)

        output.Write("<b>High: </b>")

        output.RenderEndTag()

        output.RenderBeginTag(HtmlTextWriterTag.Td)

        output.Write(mHigh)

        output.RenderEndTag()

 

        output.RenderEndTag()

        output.RenderBeginTag(HtmlTextWriterTag.Tr)

 

        output.AddAttribute(HtmlTextWriterAttribute.Align, "left")

        output.RenderBeginTag(HtmlTextWriterTag.Td)

        output.Write("<b>Low: </b>")

        output.RenderEndTag()

        output.RenderBeginTag(HtmlTextWriterTag.Td)

        output.Write(mLow)

        output.RenderEndTag()

 

        output.RenderEndTag()

        output.RenderBeginTag(HtmlTextWriterTag.Tr)

 

        output.AddAttribute(HtmlTextWriterAttribute.Align, "left")

        output.RenderBeginTag(HtmlTextWriterTag.Td)

        output.Write("<b>Volume: </b>")

        output.RenderEndTag()

        output.RenderBeginTag(HtmlTextWriterTag.Td)

        output.Write(mVolume)

        output.RenderEndTag()

 

        output.RenderEndTag()

        output.RenderBeginTag(HtmlTextWriterTag.Tr)

 

        output.AddAttribute(HtmlTextWriterAttribute.Align, "left")

        output.RenderBeginTag(HtmlTextWriterTag.Td)

        output.Write("<b>Market Cap: </b>")

        output.RenderEndTag()

        output.RenderBeginTag(HtmlTextWriterTag.Td)

        output.Write(mMktCap)

        output.RenderEndTag()

 

        output.RenderEndTag()

        output.RenderBeginTag(HtmlTextWriterTag.Tr)

 

        output.AddAttribute(HtmlTextWriterAttribute.Align, "left")

        output.RenderBeginTag(HtmlTextWriterTag.Td)

        output.Write("<b>Previous Close: </b>")

        output.RenderEndTag()

        output.RenderBeginTag(HtmlTextWriterTag.Td)

        output.Write(mPrevClose)

        output.RenderEndTag()

 

        output.RenderEndTag()

        output.RenderBeginTag(HtmlTextWriterTag.Tr)

 

        output.AddAttribute(HtmlTextWriterAttribute.Align, "left")

        output.RenderBeginTag(HtmlTextWriterTag.Td)

        output.Write("<b>Percent Change: </b>")

        output.RenderEndTag()

        output.RenderBeginTag(HtmlTextWriterTag.Td)

        output.Write(mPercentChng)

        output.RenderEndTag()

 

        output.RenderEndTag()

        output.RenderBeginTag(HtmlTextWriterTag.Tr)

 

        output.AddAttribute(HtmlTextWriterAttribute.Align, "left")

        output.RenderBeginTag(HtmlTextWriterTag.Td)

        output.Write("<b>Annual Range: </b>")

        output.RenderEndTag()

        output.RenderBeginTag(HtmlTextWriterTag.Td)

        output.Write(mAnnRange)

        output.RenderEndTag()

 

        output.RenderEndTag()

        output.RenderBeginTag(HtmlTextWriterTag.Tr)

 

        output.AddAttribute(HtmlTextWriterAttribute.Align, "left")

        output.RenderBeginTag(HtmlTextWriterTag.Td)

        output.Write("<b>Earnings: </b>")

        output.RenderEndTag()

        output.RenderBeginTag(HtmlTextWriterTag.Td)

        output.Write(mEarns)

        output.RenderEndTag()

 

        output.RenderEndTag()

        output.RenderBeginTag(HtmlTextWriterTag.Tr)

 

        output.AddAttribute(HtmlTextWriterAttribute.Align, "left")

        output.RenderBeginTag(HtmlTextWriterTag.Td)

        output.Write("<b>P-E: </b>")

        output.RenderEndTag()

        output.RenderBeginTag(HtmlTextWriterTag.Td)

        output.Write(mPE)

        output.RenderEndTag()

 

        output.RenderEndTag()

 

        output.RenderEndTag()

 

    End Sub 

#End Region

The Code:  The Demo Site's Default Page

The default.aspx page contained within the demo site serves only a test container for the control. The page contains a panel with a centered table. The table contains three columns and one row. A single custom control is added to each of the three columns. Each of the custom controls has its StockTicker property set through property editor in the IDE. Beneath the table is a button; this button carries the label "Update" and the button only serves to force a post back which in turn will force the update of each of the custom controls.

Figure 3:  Setting the StockTicker Property at Design Time

Summary

This project was intended to describe a useful, easy to build custom control. While this demonstration was limited to describing the StockTracker custom control, the same approach applied herein would work with a variety of other custom controls.

Login to add your contents and source code to this article
share this article :
post comment
 

Scott,

 

When I attempt to open the default.aspx in StockTrackerTest, I get an error message in a small box that says, “Error Creating Control – Panel1 Unknown server tag ‘cc1:StockDog’".

 

Am I missing a component or did I miss a step in the installation?

 

Thanks,

David

 

Posted by David Taylor Nov 11, 2006
Become a Sponsor
PREMIUM SPONSORS
  • ceTE software specializes in components for dynamic PDF generation and manipulation. The DynamicPDF™ product line allows you to dynamically generate PDF documents, merge PDF documents and new content to existing PDF documents from within your applications. Visit DynamicPDF here
    The leading .NET charting control now features PDF, Flash and Silverlight export, visualization of large datasets and more. Deliver true charting functionality to your BI, Scorecard, Presentation or Scientific apps. Download evaluation now.
6 Months Free & No Setup Fees ASP.NET Hosting!
Become a Sponsor