Arithmetic and string processing statements form a bulk of the processing operations to manipulate data and create meaningful information from it. Taken together, these statements represent a sequence of processing steps that the computer performs to generate information appearing on the page. There are various ways in which these statements can be packaged for placement on the page so that they are accessible and can be called upon to do their work.
Earlier, you were introduced to the Page_Load subprogram that the computer runs automatically when the page loads. In addition, you likely will need to create your own subprograms to package statements and to run whenever the need calls for it.
Subprograms
One of the primary ways in which Visual Basic code is packaged on a Web page is within a subprogram, variously call a subroutine or procedure. A subprogram has the following general structure.
A subprogram is identified by the keyword Sub at its beginning and the keywords End Sub at its end. A subprogram name is a programmer-supplied name that follows Visual Basic naming conventions. The name must be unique among the collection of subprograms on the page. Visual Basic commands, or statements, are enclosed inside the subprogram to carry out the processing for which the subprogram is created.
A subprogram may or may not require a signature. A signature is a list of variables, called arguments, that are supplied to the subprogram in order for it to carry out its processing. Various types of signatures are described below.
Recall that all subprograms must be contained inside <script> tags with the attribute runat="server". Any number of subprograms can be contained inside a single pair of <script> tags.
The Page_Load Subprogram
Subprograms are activated to perform their processing in several ways. One of the ways is to activate the subprogram every time the Web page is accessed, and prior to sending the page to the client who made the request. This particular subprogram has the required name Page_Load. It does not have a signature, although a pair of empty parentheses can be coded to indicate its absence: Page_Load().
The Page_Load subprogram is not required unless there is processing to take place every time the page opens. You might, for instance, decide to display the current date on your page. In this case the Page_Load subprogram would be an appropriate place to retrieve the system date from the server and place it in an output control on the page, prior to sending the page to the browser.
<SCRIPT runat="server"> Sub Page_Load DateOut.Text = DateString() End Sub </SCRIPT> <html> <body> <p>Today is <asp:Label id="DateOut" runat="server"/></p> </body> </html>
Other common uses for the Page_Load subprogram are to populate drop-down lists, radio buttons, and checkboxes that appear on the page, or to access a set of records from a database for display on the page.
NOTE: It is assumed in these tutorials that you are generally familiar with ASP.NET server controls. These are special HTML tags that are accessible by Visual Basic scripts and that provide the interface between data items appearing on the page and scripts that process those data items. Server controls are discussed in the ASP.NET Tutorial at this site.
The Page.IsPostBack Condition
Statements that appear in the Page_Load subprogram are run every time the page loads or is refreshed. Often times, however, it is necessary to perform the processing only the first time the page loads. This is common practice under ASP.NET where page controls automatically retain their values between post-backs of the page (when the page is reloaded due to an action of the user). All controls take part in the page's View State and their values are retained between page postings.
This need to run a script only the first time the page loads is illustrated in the above example. Since the system date is assigned to an <asp:Label> control, the value of the control will be retained and displayed if the page is posted back to the server through some user action. It is not necessary to get the system date every time the page loads.
For these situations, script statements are placed inside a Page.IsPostBack condition test. They are executed only the first time the page loads and a server control is populated with the information generated by the script. Subsequently, the control retains its information without having to repopulate it.
<SCRIPT runat="server"> Sub Page_Load If Not Page.IsPostBack Then DateOut.Text = DateString() End If End Sub </SCRIPT>
Calling Subprograms from Controls
In most cases, subprograms are called upon to do their work through explicit subprogram calls issued by server controls. Various controls have various ways of calling a subprogram and in passing information to it.
A common way for a page control to call a subprogram is through its OnClick="subprogram" event handler, naming a subprogram to run when the user clicks the control. For example, a button control,
<asp:Button OnClick="subprogram" runat="server"/>
displays a standard button on the page. When the user clicks the button, the named subprogram is run.
Subprogram Signatures
Subprograms that are called from server controls have special signatures depending on what type of control and which event handler makes the call. These signatures are in the general format shown below.
The source and arguments references are programmer-supplied names through which the control that makes the call passes two pieces of information. The source name is a reference to the properties of the particular control object which makes the call (the "source" of the call). The arguments name is a reference to any arguments that might have been passed to the subprogram by the call. Depending on the control doing the calling, there might not be any arguments passed.
The argument type of the signature depends on the type of control making the call and the particular event handler used. Special argument-type keywords must be matched with the control and the event handler. The following table gives the argument type for the server controls that call a subprogram through their various event handlers.
Accessing Passed Arguments
As a simple example of the kinds of information available through a subprogram's signature, take the case of a standard button that calls a subprogram through its OnCommand event handler.
<SCRIPT runat="server"> Sub MySubprogram (Src As Object, Args As CommandEventArgs) Identity.Text = Src.id CommandName.Text = Args.CommandName End Sub </SCRIPT> <asp:Button id="MyButton" runat="server" OnCommand="MySubprogram" CommandName="Do My Processing"/></p> Source Id = <asp:Label id="ID" runat="server"/><br/> Command Name = <asp:Label id="CommandName" runat="server"/><br/>
When the button is clicked and the subprogram is called, the button passes a reference to itself through the Src argument; its CommandName property is passed through the Args argument (remember, Src and Args are programmer-supplied names). Through the Src argument the subprogram has access to button properties such as the id value assigned to it (Src.id); through the Args argument it has access to properties such as the CommandName assigned to the button (Args.CommandName). Other types of controls pass other types of information through the signature's argument list.
All server controls include the runat="server" attribute. This means that all controls can interact with scripts on the same page. To be directly accessible from a script, a control also must be assigned a unique id value. It is through this id that a script can interact with the control. In the above example, the script can reference the two <asp:Label> controls and assign data values to them through their ids and their associated Text properties.
Certainly, the arguments passed to a subprogram can be important aspects of program processing. However, for the most part, subprograms utilize arithmetic statements, string manipulation statements, and a host of other processing statements to carry out the work of the subprogram.
Subprograms Calling Subprograms
Subprograms can call other subprograms. A typical case is where a common set of processing operations are needed by two or more other subprograms. Rather than duplicate the operations in all subprograms which need them, they are isolated in a separate subprogram which is simply called from those which require the operations.
The following is a trivial example. Click the "Start" button. Then click the "Stop" button. Your reaction time is reported.
<SCRIPT runat="server"> Sub Start_Click (Src As Object, Args As EventArgs) Set_Time End Sub Sub Stop_Click (Src As Object, Args As EventArgs) Dim StartTime, StopTime, Interval As Double StartTime = CDbl(TheTime.Text) Set_Time StopTime = CDbl(TheTime.Text) Interval = StopTime - StartTime IntervalOut.Text = Interval End Sub Sub Set_Time Dim Milliseconds As Double Milliseconds = Timer TheTime.Text = Milliseconds End Sub </SCRIPT> <asp:Button Text="Start" OnClick="Start_Click" runat="server"/> <asp:Button Text="Stop " OnClick="Stop_Click" runat="server"/> <b>Reaction time=</b><asp:Label id="IntervalOut" Text="0.0" runat="server"/> sec. <asp:Label id="TheTime" Visible="False" runat="server"/>
Without going into the details, just notice that both the Start_Click and Stop_Click subprograms make a call to subprogram Set_Time to set the number of milliseconds since midnight. The interval between the two calls is the reaction time. Although there would be nothing wrong in coding the Set_Time statements in each of the individual subprograms, there are coding efficiencies and fewer chances for coding errors by coding the routine one time in a single subprogram.
Passing Parameters
Subprograms that carry out the work of other subprograms often need to received information from the calling subprogram. Most often this information is one or more data items needed by the called subprogram to perform its task. Again, a trivial example makes the point. When a number is entered into the following text box, it is used as the upper-limit for generating a random number between 0 and that number.
Range: 0 -
SCRIPT runat="server"> Sub Get_Range (Src as Object, Args As EventArgs) Dim Low As Integer = 0 Dim High As Integer High = HighNumber.Text Get_Random (Low, High) End Sub Sub Get_Random (Low As Integer, High As Integer) RandomNumber.Text = Math.floor((High - Low + 1) * Rnd() + Low) End Sub </SCRIPT> Range: 0 - <asp:TextBox id="HighNumber" Size="2" runat="server"/> <asp:Button Text="Random Number" OnClick="Get_Range" runat="server"/> <asp:Label id="RandomNumber" runat="server"/>
The Get_Random subprogram generates and displays the random number. In order to do so it needs to know the range within which to produce the number. This range is supplied by the Get_Range subprogram when it calls Get_Random.
Calling Statement
A subprogram is provided with data values by a calling statement in the following general format.
The optional keyword Call is followed by a subprogram name, followed by a list of data items, separated by commas and contained inside a set of parentheses. This set of data items is often called the argument list of the calling statement. These arguments are usually names of variables whose values are passed to the called subprogram; however, other expressions that produce data values, or literal values, can be passed. Passed variables are those have been defined within the calling subprogram. In the above example, the calling statement Get_Random (Low, High) passes two variables, Low and High, that originate in the subprogram. Keep in mind that actual data values are passed, copies of the contents of the named variables.
The subprogram that is called receives any passed data values through its own argument list, as shown in the following general format.
An argument is a variable name along with a type specification. The type must be compatible with that of the data value being passed. The list of variables must also be in the same order as they were passed since they are matched on a one-to-one basis with the argument list in the calling statement. The argument list is a set of variable declarations, similar to coding a Dim statement for each variable. Once the subprogram receives the data values they can be treated just as any other variables originating in the subprogram.
The variable names assigned as arguments are programmer supplied, and they do not have to match the names used in the calling statement. They can have the same names, without conflict, since they are local to the subprogram and are independent of any variables appearing in the calling procedure.
Local and Global Variables
Passing of variables between subprograms highlights the issue of local versus global variables. Any variables declared within a subprogram are local and private to that subprogram and are not accessible by other subprograms that make up a script. Different subprograms can use the same names for their private variables without risk that other subprograms will inadvertently corrupt their values by referring to those names. The same names refer to entirely different variables. Still, it is not a particularly good idea to use identical variable names in more than one subprogram since the programmer might get confused even if the computer doesn't.
As best possible, all variables should be declared locally inside subprograms. However, occasions arise when two or more subprograms really need access to the same variable. Consider, for example, a variable used as a counter or as an accumulator of totals. There is the need to initialize the variable, say setting its value to 0. Then there is the need to increment the variable, say each time a subprogram is run.
This variable cannot be declared and initialized inside the same subprogram that increments it. By doing so, each time the subprogram is run the variable is reinitialized before being incremented, and an accumulation of values never takes place. Rather, the variable needs to be declared and initialized once, outside the subprogram, with the subprogram having access to the variable in order to increment it.
Variables become globally accessible -- accessible by all subprograms -- when they are declared outside of any subprograms. In the example of an accumulator variable, its declaration is shown in the following script block.
SCRIPT runat="server"> Dim Total As Decimal Sub Page_Load Total = 0.00 End Sub Sub Increment_Total() Total += value End Sub </SCRIPT>
Variable Total is declared within the script block but outside of any subprogram, making it globally accessible by any subprogram. Therefore, subprogram Page_Load can access the variable in order to initialize it; subprogram Increment_Total can access the variable in order to increment it.