Microsoft ASP .NET Professional Projects - Premier Press
.pdfPrivate ls_procedure as string Private ls_exitpage as string Private lt_datatable as datatable Private ls_mode as string Protected mytbl as table
Public Property Mode as string Get
Return Cstr(ViewState("ls_mode"))
End Get
Set
ViewState("ls_mode") = value End Set
End Property
Public Property ExitPage as string Get
Return Cstr(ViewState("ls_exitpage"))
End Get
Set
ViewState("ls_exitpage") = value End Set
End Property
Public Property t as datatable
Get
Return lt_datatable
End Get
Set
lt_datatable = value End Set
End Property
Public Property KeyField as string
Get
Return Cstr(ViewState("ls_keyfield"))
End Get
Set
ViewState("ls_keyfield") = value End Set
End Property
Public Property KeyValue as string Get
Return Cstr(ViewState("ls_keyvalue"))
End Get
Set
ViewState("ls_keyvalue") = value End Set
End Property
Public Property Procedure as string Get
Return Cstr(ViewState("ls_procedure"))
End Get
Set
ViewState("ls_procedure") = value End Set
End Property
Public Property display as string Get
Return Cstr(ViewState("ls_display"))
End Get
Set
ViewState("ls_display") = value End Set
End Property
Public Property Where as string
Get
Return Cstr(ViewState("ls_where"))
End Get
Set
ViewState("ls_where") = value
End Set
End Property
Public Property SQL as string
Get
Return Cstr(ViewState("ls_sql"))
End Get
Set
ViewState("ls_sql") = value
End Set
End Property
Public Property ConnStr as string
Get
Return Cstr(ViewState("ls_ConnStr") )
End Get
Set
ViewState("ls_ConnStr") = value
End Set
End Property
Protected Overrides Sub CreateChildControls()
Dim dv As DataView
Dim myConnection As OleDbConnection Dim myCommand As OleDbDataAdapter Dim ds As New DataSet
Dim vSql As string
If Where.Length < 1 then vSql = SQL
mode = "insert" Else
vSql = SQL + Where mode = "update"
End If
myConnection = New OleDbConnection(ConnStr) myCommand = New OleDbDataAdapter(vSql, myConnection) myCommand.Fill(ds, "vtable")
dv = new DataView(ds.Tables("vtable")) Dim Fields As Integer
'Dim t As DataTable t = dv.Table
Dim r As DataRow
Dim c As DataColumn
Dim cell As TableCell
Dim row As DataRow
Dim Fieldscount As integer
Dim s As string
Dim vdisplay As string
vDisplay = Display + "000000000000000000000000000000000000000000"
FieldsCount = 0
s = "<A HREF=" + ExitPage + ">Back</A>"
me.Controls.Add(new LiteralControl(s))
me.Controls.Add(new LiteralControl("<table bgcolor ='antiquewhite' style='font: 8pt verdana'>"))
me.Controls.Add(new LiteralControl("<tr>")) If mode = "insert" then
me.Controls.Add(new LiteralControl("<td colspan='2' bgcolor='#aaaadd' style='font:10pt verdana'>Add a New
Record:</td>"))
Else
me.Controls.Add(new LiteralControl("<td colspan='2' bgcolor='#aaaadd' style='font:10pt verdana'>Edit
Record:</td>"))
End if
me.Controls.Add(new LiteralControl("</tr>")) If mode = "update" then
For Each r in t.Rows
For Each c in t.Columns 'Don't show this field
IF vdisplay.chars(FieldsCount) = "0" or c.ToString = KeyField then Else
me.Controls.Add(new LiteralControl("<tr>")) 'label
me.Controls.Add(new LiteralControl("<td>")) me.Controls.Add(new LiteralControl(c.ToString)) me.Controls.Add(new LiteralControl("</td>")) 'value
me.Controls.Add(new LiteralControl("<td>")) Dim Box As New TextBox
Box.Text = r(c).ToString Box.ID = c.ToString me.Controls.Add(box)
me.Controls.Add(new LiteralControl("</td>")) end if
FieldsCount = FieldsCount + 1
Next c
Next r
Else ' Insert Mode
For Each c in t.Columns
IF vdisplay.chars(FieldsCount) = "0" or c.ToString = KeyField then Else
me.Controls.Add(new LiteralControl("<tr>")) 'label
me.Controls.Add(new LiteralControl("<td>")) me.Controls.Add(new LiteralControl(c.ToString)) me.Controls.Add(new LiteralControl("</td>")) 'value
me.Controls.Add(new LiteralControl("<td>")) Dim Box As New TextBox
Box.ID = c.ToString me.Controls.Add(box)
me.Controls.Add(new LiteralControl("</td>")) End if
FieldsCount = FieldsCount + 1
Next c
End If
me.Controls.Add(new LiteralControl("</tr>")) me.Controls.Add(new LiteralControl("</Table>")) '------add button
Dim AddButton As New Button if mode = "insert" then
AddButton.Text = "Add" else
AddButton.Text = "Update" end if Me.Controls.Add(AddButton)
End Sub
End Class
End Namespace
Properties and Namespaces
I have imported various namespaces in my component. These are the following:
§System
§System.Web
§System.Web.UI
§System.Web.UI.WebControls
§System.Data
§System.Data.ADO
Defining properties for the control is a neat way of allowing users to supply desired values to the control. Properties are implemented by defining accessor (get) and mutator (set) functions and a local variable. The GenEditAdd control uses eight property values as discussed above and two properties that are of internal use. Thus there are a total of ten property values.
I have thus declared ten local variables as follows:
Private ls_display as string
Private ls_where as string
Private ls_sql as string
Private ls_ConnStr as string
Private ls_keyField as string
Private ls_keyValue as string
Private ls_procedure as string
Private ls_exitpage as string
Private lt_datatable as datatable
Private ls_mode as string
The ten properties are as follows:
§Display
§Where
§SQL
§ConnStr
§KeyField
§KeyValue
§Procedure
§ExitPage
§DataTable
§Mode (insert/edit)
The DataTable and Mode properties are used internally by the control and the user does not set them. You will note that I have used the ViewState property with each of these. Thus the SQL property looks like the following:
Public Property SQL as string
Get
Return Cstr(ViewState("ls_sql"))
End Get
Set
ViewState("ls_sql") = value
End Set
End Property
The properties that are set by the users are stored in a "StateBag." The ASP.NET framework will save the state of the control when it is destroyed and restore it when it is created. The ViewState property gets the stored property from the state bag. If we don't use the state property, we will lose the property values each time a post-back occurs.
Control Composition
The simple control that I created in the start of this chapter is called a "Noncomposite Control." This was because I had to control the rendering of HTML to the browser, which I did by overriding the control's Render method and taking charge of the rendering. The GenEditAdd is called a composite control because it is composed of standard ASP.NET controls like textboxes and buttons.
The GenEditAdd control inherits from the control class. This class has an overrideable method called CreateChildControls. The purpose of this method is to create child controls on the form. There are two types of controls that I add to the form. These are LiteralControls and TextBoxes. Anytime I want to add a label or write out a string containing HTML formatting, I use the LiteralControl. For example, to add a starting table tag, I add the following LiteralControl using the method called controls.Add:
me.Controls.Add(new LiteralControl("<table bgcolor ='antiquewhite' style='font: 8pt verdana'>"))
I also add a number of textboxes to build the input form. I will be coming back to this later. I identify the mode the control is in. This can be the update or insert mode and the property called Mode is updated accordingly. This is done by the following code:
If Where.Length < 1 then
vSql = SQL
mode = "insert"
Else
vSql = SQL + Where
mode = "update"
End If
If the Where property is less than one character, the Mode property is set to "insert," else the Mode property is "update" and the where clause is added to the SQL statement.
If the Mode property is update, I iterate the DataRows and DataColumns collections as explained in Step 1, otherwise I just iterate the DataColumns collection as explained in Step 2. A number of textboxes are added to the form to receive the user input as follows:
Dim Box As New TextBox
Box.Text = r(c).ToString
Box.ID = c.ToString
me.Controls.Add(box)
Note that I give each textbox a unique id so that I can refer to it in code. This id is the name of the database column. The textboxes are enclosed within table data (<td>) tags. The table (<table>), table row (<tr>), and table data (<td>) tags are all created using LiteralControls.
I can specify the fields to display by setting the Display property. Suppose my database fields are code_value, code_display, type, opening, and closing. I do not want to display the code_value field as I do not want the user to be able to change the primary key. Also, I do not want to display the type field (this is set automatically by the stored procedure p_masters and the user should not be allowed to change it) and the
closing balance field (a database trigger will automatically update this field. This trigger, which is on the transactions table, will be explained later in the book). Hence, I will set the Display property to be 01010. Remember, a zero means hide the field and a one means show it. In the body of the control, I pad the Display property with a number of zeros as follows:
vDisplay = Display + "000000000000000000000000000000000000000000"
I do this just in case the user forgets to provide this value. A null Display property will crash the control. I then evaluate the property as follows:
If vdisplay.chars(FieldsCount) = "0" or c.ToString = KeyField Then
'Do Nothing
Else
'Proceed
End if
The chars method extracts the value of a string at a specified position. This position is provided by the FieldsCount variable, which I am incrementing in the loop. If the extracted character at the position provided by the FieldsCount variable is equal to zero or the column is the KeyColumn, then the control doesn't do anything. Otherwise, it creates a textbox with the appropriate id. Finally, I add a button that will display with a caption of "Update" in the edit mode and "Insert" in the insert mode.
The InamingContainer
Run the test web form GenTestStep3.aspx. View the source in the browser. The following is an extract of what you should see:
<A href=>Back</A>
<Table bgcolor ='antiquewhite' style='font: 8pt verdana'>
<tr><td colspan='2' bgcolor='#aaaadd' style='font:10pt verdana'>Edit Record:</td></tr>
<tr>
<td>
code_display
</td>
<td>
<input name="Gen:code_display" type="text" value="Cash in Hand "id="Gen_code_display" />
</td>
</tr>
<tr>
<td>
code_category
</td>
<td>
<input name="Gen:code_category" type="text" value="604" id="Gen_code_category"
/>
</td>
</tr>
<tr>
<td>
type
</td>
<td>
<input name="Gen:type" type="text" value="A" id="Gen_type" />
</td>
</tr>
<tr>
<td>
closing
</td>
<td>
<input name="Gen:closing" type="text" value="0" id="Gen_closing" />
</td>
</tr>
</Table>
<input type="submit" name="Gen:ctrl31" value="Update" />
Note that each textbox has an id attribute. For example, the code_display has an id of Gen_code_display. I had supplied the id of code_display in the body of the code. However, the name Gen was provided by the control on its own accord. This means all the textboxes (each having a unique id) reside within the parent control called Gen, and thus have this name prefixed to its id.
I told the ASP.NET runtime that GenEditAdd was an InamingContainer when I said that it Implements InamingContainer at the top of my code file. This is all that I need to do for the control to participate in ID and state management.
To see this for yourself, delete the Implements InamingContainer directive so that the code now says the following:
Public Class GenEditAdd: Inherits Control
Compile Step3.vb (by running step3.bat). Now run GenTestStep3.aspx and view the source of the generated HTML, as follows:
<A href=>Back</A>
<table bgcolor ='antiquewhite' style='font: 8pt verdana'>
<tr><td colspan='2' bgcolor='#aaaadd' style='font:10pt verdana'>Edit Record:</td></tr>
<tr>
<td>
code_display
</td>
<td>
<input name="code_display" type="text" value="Cash in Hand " id="code_display"
/>
</td>
</tr>
<tr>
<td>
code_category
</td>
<td>