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.
using System; using System.Collections.Generic; using System.ComponentModel; using System.Text; using System.Web; using System.Web.UI; using System.Web.UI.WebControls; using System.Xml;
[DefaultProperty("StockTicker"), ToolboxData("<{0}:StockDog runat=server></{0}:StockDog>")] public class StockDog : 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 net.webservicex.www.StockQuote mStocks; private XmlDocument mXmlDoc; private string mStockTicker; private string mLast; private string mDate; private string mTime; private string mChange; private string mOpen; private string mHigh; private string mLow; private string mVolume; private string mMktCap; private string mPrevClose; private string mPercentChng; private string mAnnRange; private string mEarns; private string mPE; private string mName; #endregion
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 void StockDog_Init(object sender, System.EventArgs e) { Fetch(StockTicker); } public void Fetch(string strStock) { mXmlDoc = new XmlDocument(); mStocks = new net.webservicex.www.StockQuote(); string strQuote = 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 XmlNodeList lastNodes; XmlNode lastNode; lastNodes = mXmlDoc.GetElementsByTagName("Last"); foreach (XmlNode tempLoopVar_lastNode in lastNodes) { lastNode = tempLoopVar_lastNode; mLast = lastNode.ChildNodes[0].Value; } // Date XmlNodeList dateNodes; XmlNode dateNode; dateNodes = mXmlDoc.GetElementsByTagName("Date"); foreach (XmlNode tempLoopVar_dateNode in dateNodes) { dateNode = tempLoopVar_dateNode; mDate = dateNode.ChildNodes[0].Value; } // Time XmlNodeList timeNodes; XmlNode timeNode; timeNodes = mXmlDoc.GetElementsByTagName("Time");
foreach (XmlNode tempLoopVar_timeNode in timeNodes) { timeNode = tempLoopVar_timeNode; mTime = timeNode.ChildNodes[0].Value; } // Change XmlNodeList changeNodes; XmlNode changeNode; changeNodes = mXmlDoc.GetElementsByTagName("Change"); foreach (XmlNode tempLoopVar_changeNode in changeNodes) { changeNode = tempLoopVar_changeNode; mChange = changeNode.ChildNodes[0].Value; } // Open XmlNodeList openNodes; XmlNode openNode; openNodes = mXmlDoc.GetElementsByTagName("Open"); foreach (XmlNode tempLoopVar_openNode in openNodes) { openNode = tempLoopVar_openNode; mOpen = openNode.ChildNodes[0].Value; } // High XmlNodeList highNodes; XmlNode highNode; highNodes = mXmlDoc.GetElementsByTagName("High"); foreach (XmlNode tempLoopVar_highNode in highNodes) { highNode = tempLoopVar_highNode; mHigh = highNode.ChildNodes[0].Value; } // Low XmlNodeList lowNodes; XmlNode lowNode; lowNodes = mXmlDoc.GetElementsByTagName("Low"); foreach (XmlNode tempLoopVar_lowNode in lowNodes) { lowNode = tempLoopVar_lowNode; mLow = lowNode.ChildNodes[0].Value; } // Volume XmlNodeList volumeNodes; XmlNode volumeNode; volumeNodes = mXmlDoc.GetElementsByTagName("Volume"); foreach (XmlNode tempLoopVar_volumeNode in volumeNodes) { volumeNode = tempLoopVar_volumeNode; mVolume = volumeNode.ChildNodes[0].Value; } // MrkCap XmlNodeList MrkCapNodes; XmlNode MrkCapNode; MrkCapNodes = mXmlDoc.GetElementsByTagName("MktCap"); foreach (XmlNode tempLoopVar_MrkCapNode in MrkCapNodes) { MrkCapNode = tempLoopVar_MrkCapNode; mMktCap = MrkCapNode.ChildNodes[0].Value; } // PrevClose XmlNodeList prevCloseNodes; XmlNode prevCloseNode; prevCloseNodes = mXmlDoc.GetElementsByTagName("PreviousClose"); foreach (XmlNode tempLoopVar_prevCloseNode in prevCloseNodes) { prevCloseNode = tempLoopVar_prevCloseNode; mPrevClose = prevCloseNode.ChildNodes[0].Value; } // mPercentChng XmlNodeList percentChngNodes; XmlNode percentChngNode; percentChngNodes = mXmlDoc.GetElementsByTagName("PercentageChange"); foreach (XmlNode tempLoopVar_percentChngNode in percentChngNodes) { percentChngNode = tempLoopVar_percentChngNode; mPercentChng = percentChngNode.ChildNodes[0].Value; } // mAnnRange XmlNodeList annRangeNodes; XmlNode annRangeNode; annRangeNodes = mXmlDoc.GetElementsByTagName("AnnRange"); foreach (XmlNode tempLoopVar_annRangeNode in annRangeNodes) { annRangeNode = tempLoopVar_annRangeNode; mAnnRange = annRangeNode.ChildNodes[0].Value; } // mEarns XmlNodeList earnsNodes; XmlNode earnsNode; earnsNodes = mXmlDoc.GetElementsByTagName("Earns"); foreach (XmlNode tempLoopVar_earnsNode in earnsNodes) { earnsNode = tempLoopVar_earnsNode; mEarns = earnsNode.ChildNodes[0].Value; } // mPE XmlNodeList PENodes; XmlNode PENode; PENodes = mXmlDoc.GetElementsByTagName("P-E"); foreach (XmlNode tempLoopVar_PENode in PENodes) { PENode = tempLoopVar_PENode; mPE = PENode.ChildNodes[0].Value; } // mName XmlNodeList nameNodes; XmlNode nameNode; nameNodes = mXmlDoc.GetElementsByTagName("Name"); foreach (XmlNode tempLoopVar_nameNode in nameNodes) { nameNode = tempLoopVar_nameNode; mName = nameNode.ChildNodes[0].Value; } } #endregion #region "Properties" [Category("Stock Symbol") ] [ Browsable(true) ] [ Description("Enter the stock ticker value.")] public string StockTicker { get { return mStockTicker; } set { mStockTicker = value; } } #endregion
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 override void RenderContents(HtmlTextWriter output) { 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> 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(); } #endregion
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.
NOTE: THIS ARTICLE IS CONVERTED FROM VB.NET TO C# USING A CONVERSION TOOL. ORIGINAL ARTICLE CAN BE FOUND ON VB.NET Heaven (http://www.vbdotnetheaven.com/).

Join the conversation! Your thoughts help the community grow.