Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Microsoft ASP .NET Professional Projects - Premier Press

.pdf
Скачиваний:
147
Добавлен:
24.05.2014
Размер:
4.63 Mб
Скачать

Private 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>