Click here to Skip to main content
15,867,453 members
Articles / Web Development / ASP.NET
Article

Roll your own ASP.NET Chart Control

Rate me:
Please Sign up or sign in to vote.
4.81/5 (148 votes)
3 Jan 20038 min read 1.2M   19.9K   385   279
How to build a chart control with full design-time support.

Dynamically generated chart for the internet.

Introduction

Have you ever wanted to build a custom web control, but lost confidence once you started to navigate the MSDN information ocean? Ever wanted to build a web control only to find out that you don't know where to start and worse yet there are no comprehensive examples available on the internet? If you have faced any or all of these situations, sit back and relax! Throughout this article I will detail the major "gotchas" relating to building a custom web control and deploy it to your web application.

About Web Controls

Web Controls should be designed with the following considerations in mind; alleviate repetitive, complex tasks and add new functionality to your web pages (web forms). After wading through numerous resources, I discovered that .NET controls for the web can come in many different varieties! In short, web controls can be broken down into 6 logical types (classes):

  • HTML Server Control
  • Web Server Control
  • Web Validation Control
  • Web User Control
  • Composite Control
  • Custom Control

Since we are going to focus on custom controls, I will limit discussion on all other types to a basic definition.

Web Controls Defined

HTML Server Controls: HTML Server Controls are HTML elements containing attributes which make them visible to, and programmable on the web server. Additionally, HTML Controls map closely to HTML elements via public properties and styles.

Web Server Control: Web Server Controls are designed to provide a quick, easy way to add functionality to your web pages. These controls provide for up and down level browser support. The core requirements for Up-level Browsers are; ECMAScript (JScript, JavaScript) support, HTML version 4.0 compliance, Supports Microsoft Document Object Model (MSDOM) and Cascading style sheets (CSS) support. Additionally, these controls can be used to build more complex server controls.

Web Validation Control: Validation controls provide you with a way to check user input in Web or HTML server controls. Attach validation controls to input controls to test what the user enters for that input control.

Web User Control: Web User Controls are created like Web Forms pages. These controls can be embedded into other Web Forms pages and are an easy way to create menus, toolbars, and other reusable elements. These types of controls always end with the extension of .ascx and must be included separately in each project that uses the control. Web User Controls are dynamically compiled at run time.

Composite Control: Composite Controls combine the functionality of two or more existing controls and can expose custom properties and events. Basic requirements for implementation: must override the CreateChildControls method inherited from Control and must implement System.Web.UI.INamingContainer interface for unique naming convention.

Custom Control: Custom Controls are fully authored, pre-compiled code (.dll) and are a good choice for dynamic web page layout. The major advantage of Custom Controls is full design-time support, to include: Toolbox Integration, Visual Designers support and interfacing with the Property Grid. These controls can be installed to the Global Assembly Cache (GAC) which will allow multiple applications to share a single control.

Classy Choices - enter System.Web.UI

The System.Web.UI namespace provides classes and interfaces that allow you to create ASP.NET server controls and pages that will appear in your Web applications as user interface elements. This namespace includes the Control class, which provides all server controls, whether HTML server controls, Web server controls, or user controls, with a common set of functionality. It also includes the Page class, which is generated automatically whenever a request is made for an .aspx file contained in your Web application. You can inherit from both of these classes. Also provided are classes which provide the server controls with data binding functionality, the ability to save the view state of a given control or page, and parsing functionality for both programmable and literal controls."

The two classes that we will focus on for the purpose of this article are UserControl and WebControls. User controls are contained in ASP.NET Web Forms pages, and offer Web developers an easy way to capture commonly used Web UI. They are instantiated and cached in ways similar to Page objects. Unlike pages, however, user controls cannot be called independently. They can only be called from the page or other user control that contains them.

The WebControl class provides the properties, methods, and events that are common to all Web server controls. You can control the appearance and behavior of a Web server control by setting properties defined in this class. For example, the background color and font color of a control are controlled by using the BackColor and ForeColor properties, respectively. On controls that can display a border, you can control the border width, the border style, and the border color by setting the BorderWidth, BorderStyle, and BorderColor properties. The size of a Web server control can be specified by using the Height and Width properties.

The behavior of the control can be specified by setting certain properties. You can enable and disable a control by setting the Enabled property. The place of the control in the tab order is controlled by setting the TabIndex property. You can specify a ToolTip for the control by setting the ToolTip property.

Enough Already! How does it work?

Now that all the basics are out of the way, lets examine the class I implemented for WebChart. The WebChart control is inherited from System.Web.UI.WebControls.WebControl. By inheriting this class I have achieved "free functionality" such as Height, Width, BackColor and ForeColor. Not bad considering this is one line of code! Additionally, I will override the Render method of MyBase to display my user drawn GDI+ chart. The following code example shows how to inherit from System.Web.UI.WebControls.WebControl:

VB
<DefaultProperty("Type"), _
                 ToolboxData("<{0}:WebChart runat=server></{0}:WEBCHART>"), _
ParseChildren(True, "WebChartItems"), ToolboxBitmapAttribute(GetType(Bitmap))> _
Public Class WebChart : Inherits System.Web.UI.WebControls.WebControl
...
End Class

The above code block is relatively easy to understand, but what's all the stuff above the class statement? These are known as attributes. When you compile your code for the runtime, it is converted into Microsoft intermediate language (MSIL) and placed inside a portable executable (PE) file along with metadata generated by the compiler. Attributes allow you to place extra descriptive information into metadata that can be extracted using runtime reflection services. The compiler creates attributes when you declare instances of special classes that derive from System.Attribute. The ToolBoxData Attribute specifies how the control will be named when placed on an ASP.NET web form. The ParseChildren Attribute must identify the indexed property you will hold your collection within. The ToolboxBitmap Attribute is used to supply a custom icon for your control. The icon must be 16 x 16 and be restricted to 16 colors. The bottom left corner of the bitmap is used as the transparency color. Lastly, the icon for this project is set as an embedded resource and is named the same as the Root Namespace.

Delving deeper into the WebChart Class, we will look at enumerations and properties:

VB
Public Enum ChartType
  Pie = 0
  Bar = 1
End Enum
    
...
    
'Chart layout fields 
Private mChartType As ChartType = ChartType.Bar

'Scalar Property
<DefaultValue(GetType(ChartType), "Bar"), Category("Chart Common"),  _
               Description("Type of chart to generate.")> _
Public Property Type() As ChartType
    Get
       Return mChartType
    End Get
    Set(ByVal Value As ChartType)
        mChartType = Value
    End Set
End Property

Scalar Property (above): Notice that the public property Type is declared as the type ChartType. This will allow the Property Type to contain a drop down box populated with the 'English' values to be displayed in the property grid. Also, by initializing the mChartType property to ChartType = ChartType.Bar you are effectively assigning a default value to your property! The Attribute DefaultValue is set to get the type ChartType via Reflection and set the value to "Bar". In the property grid default values are not bolded, values which have changed from their default property will be displayed as bold text. The Category Attribute determines which category this property will be associated with on the PropertyGrid. Last, the Description Attribute is used to give the developer an idea of what the property does.

VB
<DefaultProperty("Type"), _
               ToolboxData("<{0}:WebChart runat=server></{0}:WEBCHART>"), _
ParseChildren(True, "WebChartItems"), ToolboxBitmapAttribute(GetType(Bitmap))> _
Public Class WebChart : Inherits System.Web.UI.WebControls.WebControl

'Chart data fields - All Types
Private mWebChartItems As New WebChartItemCollection(Me)

'Indexed Property
<Category("Chart Common"), _
DesignerSerializationVisibility(DesignerSerializationVisibility.Content), _
PersistenceMode(PersistenceMode.InnerDefaultProperty), _
Description("Supply data values for selected chart.")> _
Public ReadOnly Property WebChartItems() As WebChartItemCollection
    Get
       If mWebChartItems Is Nothing Then
           mWebChartItems = New WebChartItemCollection(Me) 
       End If
       Return mWebChartItems 
    End Get 
End Property

    'This Class Handles WebChart Collection 
    <Serializable()> _
    Public Class WebChartItemCollection : _
                                 Inherits System.Collections.CollectionBase

    Private mOwner As WebChart

    Public Sub New()
    MyBase.New()
    End Sub

    Public Sub New(ByVal Owner As WebChart)
    MyBase.New()
    mOwner = Owner
    End Sub

    Private Property Owner() As WebChart
    Get
        Return CType(mOwner, WebChart)
    End Get
    Set(ByVal Value As WebChart)
        mOwner = Value
    End Set
    End Property

    Default Public ReadOnly Property Item(ByVal index As Int32) As WebChartItem
    Get
        Return CType(List.Item(index), WebChartItem)
    End Get
    End Property

    Public Function Add(ByVal Item As WebChartItem) As Integer
    Return List.Add(Item)
    End Function

    End Class
    
End Class

Indexed Property: Our indexed property WebChartItems is ReadOnly because it only controls the return of our collection object. Keep in mind that a WebChartItem is added to the WebChartCollection either through the PropertyGrid or code. This allows for static values to be added to the control or using code both charts can be dynamically populated with a DataSet or XML source. Two new Attributes can be examined on this property: DesignerSerializationVisibility - This property will control how data from our indexed property is persisted, PersistenceMode - InnerDefaultProperty specifies that the persisted data will be stored as nested elements instead of attributes of the control.

Adding WebChart to the Toolbox

In order to use the WebChart control you must first build it. After the control has been compiled, you must reference it in you ASP.NET Web Application Project. Once the control has been referenced, go to your Toolbox and right-click. Select Customize Toolbox and go to the .NET Tab and browse for the .dll you compiled. After selecting the .dll you will see an icon (see picture at top of article). If you are not sure how to do any of the above, please look in VS.NET help documentation.

Example use

Adding the control at design-time is straight forward, use it like any of the native ASP.NET Controls. However, you must insert the following XML tags into your Web.config file directly underneath the opening <SYSTEM.WEB> tag (see below). This tag allows ASP.NET to track WebChart images via Application Variable. The <httpModules> tag is required for proper WebChart operation. The following code block shows how to create a pie type WebChart dynamically with an ADO.NET DataReader Object:

REQUIRED: Place the following httpModules XML in your local Web.config.

<SYSTEM.WEB>
<httpModules>
<add name= "WebChartImageStream" type= "blong.WebControls.WebChartImageStream, blong" />
</httpModules>
<SYSTEM.WEB />

VB
Imports System.Data.SqlClient
Imports blong.WebControls

Protected Sub MakeChart()

      ' Define Objects
        Dim Chart As WebChart
        Dim i As Int32
        Dim cn As New SqlConnection(Session.Item("strConn"))
        Dim cmd As New SqlCommand("WebHitsPerMonth", cn)
        Dim dReader As SqlDataReader

        cn.Open()
        cmd.CommandType = CommandType.StoredProcedure
        dReader = cmd.ExecuteReader(CommandBehavior.CloseConnection)

        ' Override Default Constructor
        ' Copyright Symbol: Hold ALT + 0681
        Chart = New WebChart()

        With Chart
            .ID = "CodeChart"
            .Type = WebChart.ChartType.Pie

            ' Override WebChartItems for Pie Data
            Dim highVal As Single
            Dim ExplodeIndex As Int32

            While dReader.Read
                If Not IsDBNull(dReader("HitYear")) Then
                    .WebChartItems.Add(New WebChartItem(dReader("HitMonth") & _ 
                    " " & dReader("HitYear"), dReader("HitMonthCount"), False))
                    If dReader("HitMonthCount") > highVal Then
                        highVal = dReader("HitMonthCount")
                        ExplodeIndex = i - 1
                    End If
                End If
                i += 1
            End While

            'Explode High Value
            .WebChartItems(ExplodeIndex).Explode = True
            .ShowLegend = True
            .Diameter = WebChart.PieDiameter.Larger
            .ExplodeOffset = 25
            .Rotate = 70
            .Thickness = WebChart.PieThickness.Medium
            .Title = "My Run Time Chart"

            'Specify output format
            .Format = WebChart.ChartFormat.Png

        End With

        ' Add control to web form
        Me.Controls.Add(Chart)

    End Sub

WebChart Credits

Special thanks to Mohammed Banat at eSense Software, Development and Consulting, for help on HTTP streaming which allows WebChart to draw charts directly to the Output.Response stream with no additional external web pages.

WebChart History

  • Version 1.1 (1/1/2003)
    - No longer rely on implicit type casting.
    - Option Explicit/Strict enabled.
    - Removed unecessary code.
    - Added code to support image streaming, no longer writes images to disk.
  • Version 1.0 (10/24/2002)
    - Initial Release

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralImage display truncating Pin
mark sisson @firstam7-Oct-03 8:44
mark sisson @firstam7-Oct-03 8:44 
GeneralRe: Image display truncating Pin
cschubert4-Nov-03 23:03
cschubert4-Nov-03 23:03 
GeneralRe: Image display truncating Pin
mark sisson @firstam5-Nov-03 4:47
mark sisson @firstam5-Nov-03 4:47 
GeneralOther Browsers Pin
Member 6214886-Oct-03 5:57
Member 6214886-Oct-03 5:57 
GeneralThank you... Pin
pmerineau25-Sep-03 5:33
pmerineau25-Sep-03 5:33 
GeneralCannot Install Pin
DigitalBay23-Sep-03 20:27
DigitalBay23-Sep-03 20:27 
GeneralWow... Absolutely Fantastic Pin
alkex198321-Aug-03 16:09
alkex198321-Aug-03 16:09 
GeneralAny pointers to make this chart interactive Pin
Shailaja18-Aug-03 0:28
Shailaja18-Aug-03 0:28 
Questioncan you offer a c# version? Pin
coolliu13-Aug-03 1:59
coolliu13-Aug-03 1:59 
AnswerRe: can you offer a c# version? Pin
blong26-Aug-03 10:32
blong26-Aug-03 10:32 
GeneralPie color Pin
Anonymous9-Jul-03 1:38
Anonymous9-Jul-03 1:38 
GeneralBarChart Size Pin
Anonymous18-Jun-03 1:45
Anonymous18-Jun-03 1:45 
GeneralRe: BarChart Size Pin
blong19-Jun-03 10:42
blong19-Jun-03 10:42 
GeneralLine Graphing and c# Pin
harryyeh16-Jun-03 19:46
harryyeh16-Jun-03 19:46 
GeneralRe: Line Graphing and c# Pin
blong19-Jun-03 10:45
blong19-Jun-03 10:45 
QuestionFloat Values? Pin
Sven200020-May-03 17:47
Sven200020-May-03 17:47 
AnswerRe: Float Values? Pin
harryyeh16-Jun-03 19:43
harryyeh16-Jun-03 19:43 
GeneralRe: Float Values? Pin
Spiff Dog27-Apr-04 7:49
Spiff Dog27-Apr-04 7:49 
GeneralRender to stream explaination Pin
endforward10-May-03 4:46
endforward10-May-03 4:46 
GeneralRe: Render to stream explaination Pin
blong10-May-03 10:21
blong10-May-03 10:21 
Generalbarchart problem Pin
yuanchong7-May-03 19:47
yuanchong7-May-03 19:47 
GeneralRe: barchart problem Pin
blong8-May-03 7:51
blong8-May-03 7:51 
GeneralRe: barchart problem Pin
Mivano11-May-03 12:18
Mivano11-May-03 12:18 
GeneralRe: barchart problem Pin
Michela22-Sep-03 3:20
Michela22-Sep-03 3:20 
Generalsource code Pin
yuanchong6-May-03 17:25
yuanchong6-May-03 17:25 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.