饭饭TXT > 学习管理 > 《Visual Studio 2010 高级编程(英文出书版)》作者:Nick Randolph/等【完结】 > [Visual.Studio.2010.高级编程].Professional.Visual.Studio.2010.txt

第 85 页

作者:Nick Randolph/等 当前章节:15401 字 更新时间:2026-6-18 14:51

Binding Data .

575

inserting new items

You now have a sample application that enables you to browse and make changes to an existing set

of individual customers. The one missing piece is the capability to create a new customer. By default,

the Add button on the BindingNavigator is automatically wired up to the AddNew method on the

BindingSource, as shown earlier in this chapter. In this case, you actually need to set some default

values on the record that is created in the Customer table. To do this, you need to write your own

logic behind the Add button.

The first step is to remove the automatic wiring by setting the AddNewItem property of the

CustomerBindingNavigator to (None), otherwise, you will end up with two records being created

every time you click the Add button. Next, double-click the Add button to create an event handler

for it. You can then modify the default event handler as follows to set initial values for the new

customer, as well as create records in the other two tables:

Vb

Private Sub BindingNavigatorAddNewItem_Click(ByVal sender As System.Object,

ByVal e As System.EventArgs) _

Handles BindingNavigatorAddNewItem.Click

Dim drv As DataRowView

'Create record in the Customer table

drv = TryCast(Me.CustomerBindingSource.AddNew, DataRowView)

Dim customer = TryCast(drv.Row, AdventureWorksLTDataSet.CustomerRow)

customer.rowguid = Guid.NewGuid

customer.PasswordHash = String.Empty

customer.PasswordSalt = String.Empty

customer.ModifiedDate = Now

customer.FirstName = "<first name>"

customer.LastName = "<last name>"

customer.NameStyle = False

Me.CustomerBindingSource.EndEdit()

End Sub

c#

private void bindingNavigatorAddNewItem_Click(object sender, EventArgs e){

DataRowView drv;

//Create record in the Customer table

drv = this.customerBindingSource.AddNew() as DataRowView;

var customer = drv.Row as AdventureWorksLTDataSet.CustomerRow;

customer.rowguid = Guid.NewGuid();

customer.PasswordHash = String.Empty;

customer.PasswordSalt = String.Empty;

customer.ModifiedDate = DateTime.Now;

customer.FirstName = "<first name>";

customer.LastName = "<last name>";

customer.NameStyle = false;

this.customerBindingSource.EndEdit();

}

576 .

chaPter 27 dATASeTS And dATAbinding

From this example, it seems that you are unnecessarily setting some of the properties — for

example, PasswordSalt and PasswordHash being equal to an empty string. This is necessary to

ensure that the new row meets the constraints established by the database. Because these fields

cannot be set by the user, you need to ensure that they are initially set to a value that can be

accepted by the database. Clearly, for a secure application, the PasswordSalt and PasswordHash

would be set to appropriate values.

Running the application with this method instead of the automatically wired event handler enables

you to create a new Customer record using the Add button. If you enter values for each of the

fields, you can save the changes.

Validation

In the previous section, you added functionality to create a new customer record. If you

don’t enter appropriate data upon creating a new record — for example, if you don’t enter a

first name — this record will be rejected when you click the Save button. The schema for the

AdventureWorksDataSet contains a number of constraints, such as FirstName can’t be null, which

are checked when you perform certain actions, such as saving or moving between records. If these

checks fail, an exception is raised. You have two options. One, you can trap these exceptions,

which is poor programming practice, because exceptions should not be used for execution control.

Alternatively, you can preempt this by validating the data prior to the schema being checked.

Earlier in the chapter, when you learned how the BindingNavigator automatically wires the

AddNew method on the BindingSource, you saw that the OnAddNew method contains a call to a

Validate method. This method propagates up and calls the Validate method on the active control,

which returns a Boolean value that determines whether the action will proceed. This pattern is used

by all the automatically wired events and should be used in the event handlers you write for the

navigation buttons.

The Validate method on the active control triggers two events — Validating and Validated —

that occur before and after the validation process, respectively. Because you want to control the

validation process, add an event handler for the Validating event. For example, you could add an

event handler for the Validating event of the FirstNameTextBox control:

Vb

Private Sub FirstNameTextBox_Validating(ByVal sender As System.Object, _

ByVal e As System.ComponentModel.CancelEventArgs) _

Handles FirstNameTextBox.Validating

Dim firstNameTxt As TextBox = TryCast(sender, TextBox)

If firstNameTxt Is Nothing Then Return

e.Cancel = (firstNameTxt.Text = String.Empty)

End Sub

c#

private void firstNameTextBox_Validating(object sender, CancelEventArgs e){

var firstNameTxt = sender as TextBox;

if (firstNameTxt == null) return;

e.Cancel = (firstNameTxt.Text == String.Empty);

}

Binding Data .

577

Though this prevents users from leaving the

textbox until a value has been added, it doesn’t

give them any idea why the application prevents

them from proceeding. Luckily, the .NET

Framework includes an ErrorProvider control

that can be dragged onto the form from the

Toolbox. This control behaves in a manner similar

to the tooltip control. For each control on the

form, you can specify an Error string, which,

when set, causes an icon to appear alongside

the relevant control, with a suitable tooltip

displaying the Error string. This is illustrated

in Figure 27-14, where the Error string is set

for the FirstNameTextBox.

Clearly, you want only to set the Error string

property for the FirstNameTextBox when there is

no text. Following from the earlier example in which you added the event handler for the Validating

event, you can modify this code to include setting the Error string:

Vb

Private Sub FirstNameTextBox_Validating(ByVal sender As System.Object, _

ByVal e As System.ComponentModel.CancelEventArgs) _

Handles FirstNameTextBox.Validating

Dim firstNameTxt As TextBox = TryCast(sender, TextBox)

If firstNameTxt Is Nothing Then Return

e.Cancel = (firstNameTxt.Text = String.Empty)

If String.IsNullOrWhiteSpace(firstNameTxt.Text) Then

Me.ErrorProvider1.SetError(firstNameTxt, "First Name must be specified")

Else

Me.ErrorProvider1.SetError(firstNameTxt, Nothing)

End If

End Sub

c#

private void firstNameTextBox_Validating(object sender, CancelEventArgs e){

var firstNameTxt = sender as TextBox;

if (firstNameTxt == null) return;

e.Cancel = (firstNameTxt.Text == String.Empty);

if (String.IsNullOrEmpty(firstNameTxt.Text)){

this.errorProvider1.SetError(firstNameTxt, "First Name must be specified");

}

else{

this.errorProvider1.SetError(firstNameTxt, null);

}

}

You can imagine that having to write event handlers that validate and set the error information for each

of the controls can be quite a lengthy process. Rather than having individual validation event handlers for

fiGure 27-14

578 .

chaPter 27 dATASeTS And dATAbinding

each control, you may want to rationalize them into a single event handler that delegates the validation to

a controller class. This helps ensure your business logic isn’t intermingled within your user interface code.

customized datasets

At the moment, you have a form that displays some basic information about a customer. However,

it is missing some of her address information, namely her Main Office and/or Shipping addresses.

If you look at the structure of the AdventureWorksLT database you will notice that there is a manyto-

many relationship between the Customer and Address tables, through the CustomerAddress

linking table. The CustomerAddress has a column AddressType that indicates the type of address.

While this structure supports the concept that multiple Customers may have the same address, the

user interface you have built so far is only interested in the address information for a particular

customer. If you simply add all three of these tables to your DataSet you will not easily be able to

use data binding to wire up the user interface. As such it is worth customizing the generated DataSet

to merge the CustomerAddress and Address tables into a single entity.

Open up the DataSet designer by double-clicking the AdventureWorksLTDataSet.xsd in the

Solution Explorer. Select the AddressTableAdapter, which you should already have from earlier in

the chapter, expand out the SelectCommand property in the Properties tool window, and then click the

ellipses next to the CommandText property. This will again open up the Query Builder. Currently, you

should only have the Address table in the diagram pane. Right-click in that pane, select Add Table,

and then select the CustomerAddress table. Check all fields in the CustomerAddress table except

AddressID and then go to the Criteria pane and change the Alias for the rowguid and ModifiedDate

columns coming from the CustomerAddress table. The result should look similar to Figure 27-15.

fiGure 27-15

Binding Data .

579

When you click the OK button you will be prompted to regenerate the Update and Insert

statements. The code generator can’t handle multiple table updates so will fail regardless of which

option you select. This means that you need to manually define the update, insert, and delete

statements. You can do this by defining stored procedures within the AdventureWorksLT database

and then to update the CommandType and CommandText for the relevant commands in the

AddressTableAdapter as shown in Figure 27-16.

Now that your DataSet contains both Customer and Address DataTables, the only thing missing

is the relationship connecting them. As you have customized the Address DataTable the designer

hasn’t been able to automatically create the relationship. To create a relation, right-click anywhere

on the DataSet design surface and select Add . Relation. This opens the Relation dialog as shown

in Figure 27-17.

fiGure 27-16 fiGure 27-17

In accordance with the way the Address DataTable has been created by combining the

CustomerAddress and Address tables, make the Customer DataTable the parent and the Address the

child. When you accept this dialog you will see a relationship line connecting the two DataTables on

the DataSet design surface.

bindingsource chains and the dataGridView

After completing the setup of the DataSet with the Customer and Address DataTables you are ready

to data bind the Address table to your user interface. So far you’ve been working with simple input

controls such as textboxes, drop-down lists, and labels, and you’ve seen how the BindingNavigator

enables you to scroll through a list of items. Sometimes it is more convenient to display a list of

580 .

chaPter 27 dATASeTS And dATAbinding

items in a grid. This is where the DataGridView is useful, because it enables you to combine the

power of the BindingSource with a grid layout.

In this example, you extend the Customer Management interface by adding address information

using a DataGridView. Returning to the Data Sources window, select the Address node from under

the Customer node. From the drop-down list, select DataGridView and drag the node into an empty

area on the form. This adds the appropriate BindingSource and TableAdapter to the form, as well as

a DataGridView showing each of the columns in the Address table, as shown in Figure 27-18.

fiGure 27-18

If you recall from earlier, the CustomerBindingSource has the AdventureWorksLTDataSet as

its DataSource, with the Customer table set as the DataMember. This means that controls

that are data bound using the CustomerBindingSource are binding to a field in the Customer

table. If you look at the AddressBindingSource you will see that its DataSource is actually the

CustomerBindingSource, with its DataMember set to Customer_Address, which is the relationship

you created between the two DataTables. As you would expect, any control being data bound using

the AddressBindingSource is binding to a field in the Address table. However, the difference is that

unlike the CustomerBindingSource, which returns all Customers, the AddressBindingSource is only

populated with the Addresses that are associated with the currently selected Customer.

Unlike working with the Details layout, when you drag the DataGridView onto the form it ignores

any settings you might have specified for the individual columns. Instead, every column is added to

Working with Data sources .

581

the grid as a simple text field. To modify

the list of columns that are displayed, you

can either use the smart tag for the newly

added DataGridView or select Edit Columns

from the right-click context menu. This

will open the Edit Columns dialog

(shown in Figure 27-19), in which columns

can be added, removed, and reordered.

After specifying the appropriate columns, the

finished application can be run, and the list of

orders will be visible for each customer in the

database.

fiGure 27-19

workinG with data

sources

In this chapter you have been working with a strongly typed DataSet that contains a number of

rows from the Customer table, based on a Title parameter. So far the example has only had one

tier, which is the Windows Forms application itself. In this section you see how you can use Visual

Studio 2010 to build a multi-tier application.

Start by creating two new projects, CustomerBrowser (Windows Forms Application) and

CustomerService (ASP.NET Web Service Application). Change the Application Type of the initial

project to Class Library by double-clicking the Properties node in Solution Explorer and then

目录
设置
设置
阅读主题
字体风格
雅黑 宋体 楷书 卡通
字体大小
适中 偏大 超大
保存设置
恢复默认
手机
手机阅读
扫码获取链接,使用浏览器打开
书架同步,随时随地,手机阅读
首 页 < 上一章 章节列表 下一章 > 尾 页