Tải bản đầy đủ - 0 (trang)
4 Focus on Problem Solving: Home Repair Services Application

4 Focus on Problem Solving: Home Repair Services Application

Tải bản đầy đủ - 0trang

5.4 Focus on Problem Solving: Home Repair Services Application



Tutorial Steps

Step 1:



Open the RepairServices Database project that you last worked on in Tutorial 5-3.



Step 2:



Open RepairServicesDataSet.xsd from the Solution Explorer window.



Step 3:



In the DataSet Designer window, right-click the AppointmentsTableAdapter

and select Properties, as shown in Figure 5-20.



Figure 5-20 AppointmentsTableAdapter properties window



Step 4:



In the Properties window, find the InsertCommand property and expand it so

you can view its CommandText subproperty. Click on the button containing

three dots to open the Query Builder window.



Step 5:



Verify that the SQL query is the following, and change it if necessary:

INSERT INTO Appointments

(TypeId, Description, Licensed, CustId, Scheduled)

VALUES (@TypeId,@Description,@Licensed,@CustId,@Scheduled)



Step 6:



Add a middle-tier class named Appointments.vb to the project. In this class,

declare the following class-level variables:

Private adapter As New _

RepairServicesDataSetTableAdapters.AppointmentsTableAdapter

Public Shared Property LastError As String



The variable named adapter is an instance of the TableAdapter that you will

use to carry out actions on the database. LastError will hold error messages

generated by the TableAdapter methods.

Step 7:



Create a new method named Insert.

1: Public Function Insert(ByVal typeId As Short,

2:

ByVal description As String, ByVal licensed As Boolean,

3:

ByVal custId As Short, ByVal Scheduled As DateTime) _

As Boolean



257



258



Chapter 5



Database Applications



4:

' Insert a new row into the Appointments table. Return

5:

' True if successful. If an exception is thrown,

6:

' LastError will hold an error message.

7:

Try

8:

LastError = String.Empty

9:

adapter.Insert(typeId, description, licensed,

10:

custId, Scheduled)

11:

Return True

12:

Catch ex As Exception

13:

LastError = ex.Message

14:

Return False

15:

End Try

16: End Function



Line 8 clears any error message that might be left over in the LastError variable from a previous operation. Line 9 calls the Insert method from the

AppointmentsTableAdapter class. If no exception is thrown, line 11 returns

True, indicating success. On the other hand, if the call to Insert on line 9

throws an exception, ErrorMessage is assigned a string and the method

returns False.



T I P : There is one possible outcome that we are ignoring in the code for

the Insert method. The call to adapter.Insert might not throw an exception, but it might somehow fail to insert a table row. It would complicate

your code to check for this remote possibility, so you can leave the code

as is.



Step 8:



Add a Shared method named CombinedDateTime that receives a date and a

time and returns a combined date/time value.

Public Shared Function CombinedDateTime(ByVal aDate As DateTime,

ByVal aTime As DateTime) As DateTime

Dim ts As New TimeSpan(aTime.Hour, aTime.Minute, 0)

Return aDate.Add(ts)

End Function



It is not possible to directly add a time to a date, but you can add a TimeSpan

object to it. The code above does just that. It is a shared method because it

does not use any class-level variables in the Appointment class, and therefore

does not require the user to create an Appointment object.

New Appointment Form

Next, you will create a New Appointment form, which will test the Appointments.Insert

method. For the moment, we will not create a user interface.

Step 9:



Add a new form named NewAppointmentForm.vb to the project. Set its Text

property to New Repair Appointment. Add the following line of code to the

form’s class:

Private mAppointments As New Appointments



This line creates an instance of the middle-tier Appointments class inside the

form, so we can call its Insert method.



5.4 Focus on Problem Solving: Home Repair Services Application



Step 10: Add a button to the form, with the Text equal to Save. Insert the following



code in the button’s Click handler:

mAppointments.Insert(2,"Fix disposal",False,1020,

#10/5/2011 9:00 AM#)

AppointmentsForm.ShowDialog()



The first statement insert a new appointment in the database. The second

statement displays the complete list of appointments in a separate form, so

you can verify that the appointment was created.

Step 11: Set the project’s startup form to NewAppointmentForm and run the applica-



tion. You should see the Appointments table appear in a grid, with the new

appointment added to the end. A sample is shown in Figure 5-21.

Figure 5-21 Appointments table, with new row added



If you should restart the application and click the button again, it would add

another row with the same information to the Appointments table. Each

appointment would have a different value in the ApptId column because that

value is generated automatically by the database.

Step 12: When you’re done, rebuild the project from the Visual Studio Build menu.



That will reset the database to its original values.



Tutorial 5-7:

Creating the main startup form

In this tutorial, you will create a startup form for the Home Repair Services application.

You will create a menu that displays all existing forms.

Tutorial Steps

Step 1:



Add a new form named MainForm.vb to the project, and set its Text property

to Home Repair Services.

Modify the project properties to make it the application startup form.



259



260



Chapter 5



Database Applications



Step 2:



Add a MenuStrip control with the following menu structure:

File

Exit

Appointments

New

View

Appointment List

Customers

View



As another option, you may want to rename the menu items to be more

descriptive than the default names assigned by Visual Studio. For example, the

names could be AppointmentsNewMenuItem, AppointmentsViewMenuItem,

and so on.

Step 3:



Create a Click event handler for the File / Exit menu item, and insert a

Me.Close() statement.



Step 4:



Create a Click event handler for the Appointments / New menu item, and

insert the following statement:

NewAppointmentForm.ShowDialog()



Step 5:



Create a Click event handler for the Appointments / View menu item, and

insert the following statement:

AppointmentsForm.ShowDialog()



Step 6:



Create a Click event handler for the Customers / View menu item, and insert

the following statement:

CustomersForm.ShowDialog()



Step 7:



Run the application and test it as follows:



Input



Select Appointments / New from the menu.



Expected result



The New Appointment form displays.



Input



Input



Close the New Appointment form, and select Appointments /

View from the menu.

The Appointments form displays, showing a grid that lists all

appointments.

Close the Appointments form, and select Customers / View from

the menu.

The Customers form displays, showing a grid that lists all

customers.

Close the Customers form. Select File / Exit from the menu.



Expected result



The startup form closes and the application ends.



Expected result

Input

Expected result



Summary

It is useful to create a menu on the startup form so you can use it as a branching point

to all the other forms in the application. Then, as you add each new form to the project, you will create a click handler for the appropriate menu item. In Tutorial 5-8, you

will add more classes and methods to the application’s middle tier.



5.4 Focus on Problem Solving: Home Repair Services Application



Tutorial 5-8:

Adding classes to the middle tier

In this tutorial, you will add the Customers and RepairTypes classes to the Home Repair

Services application’s middle tier. These classes will provide important links to the CustomersTableAdapter and RepairTypesTableAdapter, which are part of the data access

tier. You will also add methods that retrieve lists of repair types and customer names.

Tutorial Steps

Step 1:



Add a new middle-tier class named RepairTypes to the project.



Step 2:



Add the following class-level variable to the RepairTypes class:

Private adapter As New _

RepairServicesDataSetTableAdapters.RepairTypesTableAdapter



Step 3:



Create a ReadOnly property named Items that returns a DataTable containing all of the repair types.

1: Public ReadOnly Property Items() As DataTable

2: Get

3:

Dim table As DataTable = adapter.GetData()

4:

table.DefaultView.Sort = "Description"

5:

Return table

6: End Get

7: End Property



A middle-tier class gives you the opportunity to refine the data returned by a

table adapter. In the Item method shown here, line 3 calls the table adapter’s

GetData method, which returns a DataTable containing all the repair types

listed in the RepairTypes database table. Line 4 sorts the data by description,

and line 5 returns the sorted table.

Step 4:



Add a new middle-tier class named Customers to the project.



Step 5:



Add the following class-level variable to the Customers class:

Private adapter As New _

RepairServicesDataSetTableAdapters.CustomersTableAdapter



Step 6:



Create a ReadOnly property named Items that returns a DataTable containing all of the Customers:

Public ReadOnly Property Items() As DataTable

Get

Dim table As DataTable = adapter.GetData()

table.DefaultView.Sort = "Name"

Return table

End Get

End Property



Summary

Step by step, you are building up the classes in the middle tier. As you may have noticed,

you do not have to invest very much time in these classes at the beginning. It is best to

keep them short and wait until you need some new operation before adding more code.

Building the classes in the middle tier should always be done before finishing the user

interface in the presentation tier. Then the presentation tier will be able to call methods

and properties in these classes. At this point, you have created all the necessary support

for the New Appointments form.



261



262



Chapter 5



Database Applications



Runtime Data Binding

Runtime data binding means to bind a control to a data source at runtime, using code

statements. One example of this is to assign a DataTable object to the DataSource property of

a DataGridView control. In Chapter 4, you used Visual Studio to create TableAdapter,

BindingSource, and DataSet components on every form. But multi-tier applications automatically separate the presentation layer from the data components. Therefore, the best approach is

not to fill a form with data component objects, but instead to perform runtime data binding.

If you want to fill a grid or list box using runtime data binding, do the following: Declare a

variable in the form’s code that is an instance of a middle-tier class. Then call a method from

that class that returns a DataTable. Assign the DataTable to the DataSource property of a

ListBox, ComboBox, or DataGridView control. In ListBox and ComboBox controls, you

also need to set two other string properties:

• DisplayMember—The name of the DataTable column that will be displayed in the list.

• ValueMember—The name of the DataTable column that will provide a reference value

when the user selects a member of the list. The reference value will be available in the

SelectedValue property at runtime.

For example, let’s assume that the variable mRepairTypes is an instance of the RepairTypes

class. In that class, the Items property returns a DataTable object. We want the Description

column of the table to display in the combo box, and we want the TypeId column to be

returned in the combo box’s SelectedValue property when the user makes a selection. This

is the appropriate setup code, which would be in the Form_Load event handler of the form:

cboRepairType.DataSource = mRepairTypes.Items

cboRepairType.DisplayMember = "Description"

cboRepairType.ValueMember = "TypeId"



Formatting DataGridView Columns at Runtime

A disadvantage to runtime data binding is that it does not give you a chance to format

DataGridView columns in design mode. There is a simple workaround: You can temporarily

bind the grid to an existing data source just long enough to format the columns in design

mode. Then, at runtime, you can still assign a DataTable to the grid’s DataSource property.

On the other hand, if you just need to make only minor formatting changes to grid columns,

you can assign values to each column’s DefaultCellStyle property. This is done at runtime,

usually in the Form_Load event handler. The following lines, for example, set column 2 to

a numeric format, centered, with two decimal places, in a blue color:

With dgvCourses.Columns(2).DefaultCellStyle

.Format = "n"

.ForeColor = Color.Blue

.Alignment = DataGridViewContentAlignment.MiddleCenter

End With



In the MSDN documentation, you can discover the other column formatting properties.

SelectedIndexChanged Event

If your Form_Load event handler assigns a value to the DataSource property of a ListBox

or ComboBox control, a SelectedIndexChanged event is fired immediately, before the grid

has been filled with data. If there is a handler for this event that responds to user selections,

your program code might think that a selection has already been made by the user. Such a

situation can cause an exception to be thrown. Here is a workaround: First, declare a

Boolean variable that is initially set to True. Then set it to False at the end of the Form_Load

event handler. Then in the SelectedIndexChanged event handler, process the event only if the



5.4 Focus on Problem Solving: Home Repair Services Application



Boolean variable equals False. Here is an outline of the code we have described, using a

ComboBox named cboCustomers:

Private formLoading As Boolean = True

Private Sub Form_Load() Handles MyBase.Load

cboCustomers.DataSource = mCustomers.Items

.

.

formLoading = False

End Sub

Private Sub cboCustomer_SelectedIndexChanged() _

Handles cboCustomer.SelectedIndexChanged

If Not formLoading Then

' OK to process the event

End If

End Sub



In Tutorial 5-9, you will build the user interface for the New Appointment form.



Tutorial 5-9:

Adding controls to the New Appointment form

In this tutorial, you will add controls to the New Appointment form in the Home

Repair Services application. This form permits the user to input appointment data and

add a new row to the Appointments database table. Your code will call methods from

three middle-tier classes: Customers, Appointments, and RepairTypes.

Tutorial Steps

Step 1:



Open the design window for NewAppointmentForm.vb. Using the example in

Figure 5-22 and the list of named controls in Table 5-3, add the necessary controls to the form.



Figure 5-22 New Appointment form



263



264



Chapter 5



Database Applications



Table 5-3 Controls on the New Appointment form

Control Type



Control Name



Property Settings



Form



NewAppointmentForm



Text = New Repair Appointment,

AcceptButton = btnSave

CancelButton = btnCancel

FormBorderStyle = FixedDialog

MaximizeBox = False

MinimizeBox = False

Font.Size = 10



TextBox

TextBox

DateTimePicker

ComboBox

ComboBox

CheckBox

Label

Button

Button



txtTime

txtDescription

dtpDate

cboCustomer

cboRepairType

chkLicensed

lblStatus

btnSave

btnCancel



ErrorProvider



errProvider



MultiLine = True

Format = Short



Text = Must be licensed

AutoSize = False

Text = Save

Text = Cancel



The two combo boxes are important because they provide lists of customers

and repair types. When the user selects values from these lists, their corresponding ID values will be saved in the new repair appointment. Next, you

will add code to the form that calls methods from the Appointments, RepairTypes, and Customers classes in the middle tier.

Step 2:



Open the form’s code window and add new class-level variables so you now

have the following:

Private mAppointments As New Appointments

Private mRepairTypes As New RepairTypes

Private mCustomers As New Customers



Each object declared here is an instance of a middle-tier class. This is a common pattern that will repeat itself in nearly every form.

Step 3:



Create the following Form_Load event handler:

1: Private Sub NewAppointmentForm_Load() Handles MyBase.Load

2:

' Fill the Repair Types combo box.

3:

cboRepairType.DataSource = mRepairTypes.Items

4:

cboRepairType.DisplayMember = "Description"

5:

cboRepairType.ValueMember = "TypeId"

6:

7:

' Fill the Customers combo box.

8:

cboCustomer.DataSource = mCustomers.Items

9:

cboCustomer.DisplayMember = "Name"

10:

cboCustomer.ValueMember = "CustId"

11: End Sub



5.4 Focus on Problem Solving: Home Repair Services Application



The purpose of this code is to fill the two combo boxes with lists of customers and repair types. Line 3 calls the Items property from the RepairTypes

class, which returns a DataTable that lists all the possible repair types. Lines

8–10 bind another combo box with a DataTable containing customer names

and IDs.

Step 4:



Create the following Click handler for the Save button. You may already have

a Click handler, so replace it with this one:

1: Private Sub btnSave_Click() Handles btnSave.Click

2:

Dim Scheduled As DateTime

3:

Try

4:

Scheduled = Appointments.CombinedDateTime(

5:

dtpDate.Value.Date, CDate(txtTime.Text))

6:

Catch

7:

errProvider.SetError(txtTime,

8:

"Please enter a valid appointment time")

9:

Return

10:

End Try

11:

Dim typeId As Short = CShort(cboRepairType.SelectedValue)

12:

Dim custId As Short = CShort(cboCustomer.SelectedValue)

13:

Dim licensed As Boolean = chkLicensed.Checked

14:

If mAppointments.Insert(typeId, txtDescription.Text,

15:

licensed, custId, Scheduled) Then

16:

Me.Close()

17:

Else

18:

lblStatus.Text = "Cannot Add Appointment. " _

19:

& Appointments.LastError

20:

End If

21: End Sub



Lines 4–5 call the utility method from the Appointment class that combines

a date and a time, and assigns the result to the Scheduled variable. If the

date conversion throws an exception, it will be caught on line 7, where the

ErrorProvider control will display an error message.

Lines 11–12 get the repair-type ID and the customer ID from the two

combo boxes, and line 13 gets the licensed value from the check box. Line

14 calls the Insert method in the Appointments class, passing all the

required values. If the Insert method returns False, an error message is displayed by line 18. Finally, line 16 closes the form as soon as the appointment is saved.

Step 5:



Add the following Click handler for the Cancel button, and save the project.

Private Sub btnCancel_Click() Handles btnCancel.Click

Me.Close()

End Sub



Code Listing

Check the following complete code listing of the NewAppointmentForm.vb class, to

make sure you haven’t left anything out:

Public Class NewAppointmentForm

Private mAppointments As New Appointments

Private mRepairTypes As New RepairTypes

Private mCustomers As New Customers



265



266



Chapter 5



Database Applications



Private Sub NewAppointmentForm_Load() Handles MyBase.Load

cboRepairType.DataSource = mRepairTypes.Items

cboRepairType.DisplayMember = "Description"

cboRepairType.ValueMember = "TypeId"

cboCustomer.DataSource = mCustomers.Items

cboCustomer.DisplayMember = "Name"

cboCustomer.ValueMember = "CustId"

End Sub

Private Sub btnSave_Click() Handles btnSave.Click

Dim scheduledAt As DateTime

Try

scheduledAt = Appointments.CombinedDateTime(

dtpDate.Value.Date, CDate(txtTime.Text))

Catch

errProvider.SetError(txtTime,

"Please enter a valid appointment time")

Return

End Try

Dim typeId As Short = CShort(cboRepairType.SelectedValue)

Dim custId As Short = CShort(cboCustomer.SelectedValue)

Dim licensed As Boolean = chkLicensed.Checked

If mAppointments.Insert(typeId, txtDescription.Text,

licensed, custId, scheduledAt) Then

Me.Close()

Else

lblStatus.Text = "Cannot Add Appointment. " _

& Appointments.LastError

End If

End Sub

Private Sub btnCancel_Click() Handles btnCancel.Click

Me.Close()

End Sub

End Class



Ready to Test

Step 6:



Double-click on My Project in Solution Explorer and verify that the project’s

startup form is MainForm.



Step 7:



Run the application. Select Appointments / New from the menu to display the

New Appointment window. Input and save an appointment. From the main

menu, select Appointments / View and verify that the appointment you added

is now visible in the grid.



Step 8:



Add a few more appointments and verify that they were saved.



Step 9:



Close the application. Then rebuild the project from the Visual Studio Build

menu to erase the appointments you added to the database.



Summary

After writing code for the New Appointment form, we hope that you are beginning

to see how the classes in a three-tier application communicate with each other. For

example, when creating a new appointment, the NewAppointmentForm class calls

the Insert method in the Appointments class. To do that, the form must contain an

Appointment object. Then the Appointments.Insert method calls the Insert method in



5.4 Focus on Problem Solving: Home Repair Services Application



the AppointmentsTableAdapter class. To do that, the Appointments class must contain

a TableAdapter object. These steps are shown by a concept diagram in Figure 5-23.

In Tutorial 5-10, you will add the ability for users to search for appointments.

Figure 5-23 Communication between classes when adding a new appointment

NewAppointmentForm

class



has



Button Click

handler



contains



Appointments

object



calls



has



Insert

method



contains



AppointmentsTableAdapter

object



calls



has



Insert

method



Tutorial 5-10:

Searching for appointments

In this tutorial, you will add searching capabilities to the Home Repair Services application. You will modify both the Appointments form and the Appointments class.

Tutorial Steps

Step 1:



Open the Appointments.vb class and insert the following method, which

returns all the rows of the Appointments table in the database:

Public ReadOnly Property Items As DataTable

Get

Return adapter.GetData()

End Get

End Property



Step 2:



Create the GetByCustomerId method, which returns a DataTable containing

appointments for a single customer:

1 Public Function GetByCustomerId(ByVal custId As Short) As

DataTable

2

Dim table As DataTable = adapter.GetData()

3

table.DefaultView.RowFilter = "CustId = " & custId

4

Return table

5 End Function



Line 2 gets all rows from the Appointments table, and line 3 applies a filter

expression that limits the rows to a single customer ID. Line 4 returns the filtered table. This method is a good example of how code in the application’s



267



Tài liệu bạn tìm kiếm đã sẵn sàng tải về

4 Focus on Problem Solving: Home Repair Services Application

Tải bản đầy đủ ngay(0 tr)

×
x