1. Right-click the UserControls folder in Solution Explorer and select Add New Item ➤ Web User Control. Choose OrderDetailsAdmin.ascx for the name of the new user control.
2. Open the control in Design View and populate it as shown in Figure 10-11. The properties for each con- stituent control are shown in Table 10-5, and the GridView columns are listed in Table 10-6. For the GridView control, you also need to set its AutoGenerateColumns property to False.
Figure 10-11. OrderDetailsAdmin.ascx in Design View
■ Tip When setting controls’ properties, remember that Visual Studio .NET allows you to set properties on more than one control at a time—you can select, for example, the TextBox controls on the right and set their Width to 400px, and so on.
Table 10-5. Setting Controls’ Properties in OrderDetailsAdmin.ascx
Control Type ID Text CssClass Width
Label orderIdLabel Order #000 AdminTitle
Label totalAmountLabel (empty) ProductPrice
TextBox dateCreatedTextBox AdminPageText 400px
TextBox dateShippedTextBox AdminPageText 400px
CheckBox verifiedCheck AdminPageText 400px
CheckBox completedCheck AdminPageText 400px
CheckBox canceledCheck AdminPageText 400px
TextBox commentsTextBox AdminPageText 400px
TextBox customerNameTextBox AdminPageText 400px
TextBox shippingAddressTextBox AdminPageText 400px
TextBox customerEmailTextBox AdminPageText 400px
Button editButton Edit SmallButtonText 100px
Button updateButton Update SmallButtonText 100px
Button cancelButton Cancel SmallButtonText 100px
Button markVerifiedButton Mark Order as Verified SmallButtonText 305px Button markCompletedButton Mark Order as Completed SmallButtonText 305px Button markCanceledButton Mark Order as Canceled SmallButtonText 305px Label (doesn’t matter) The order contains
these items:
AdminPageText
GridView grid 100%
Table 10-6. Setting the Fields of the GridView Control
Column Type Header Text Data Field Other Properties
BoundField Product ID ProductID Read Only
BoundField Product Name ProductName Read Only
BoundField Quantity Quantity Read Only
BoundField Unit Cost Unit Cost Read Only
ButtonField Subtotal Subtotal Read Only
8213592a117456a340854d18cee57603
To make sure we’re on the same page, here’s the source code of the control:
<%@ Control Language="C#" AutoEventWireup="true"
CodeFile="OrderDetailsAdmin.ascx.cs" Inherits="OrderDetailsAdmin" %>
<asp:Label ID="orderIdLabel" runat="server"
CssClass="AdminTitle" Text="Order #000" />
<br /><br />
<table class="AdminPageText">
<tr>
<td width="130">Total Amount:</td>
<td>
<asp:Label ID="totalAmountLabel" runat="server"
CssClass="ProductPrice" />
</td>
</tr>
<tr>
<td width="130">Date Created:</td>
<td>
<asp:TextBox ID="dateCreatedTextBox" runat="server" Width="400px" />
</td>
</tr>
<tr>
<td width="130">Date Shipped:</td>
<td>
<asp:TextBox ID="dateShippedTextBox" runat="server" Width="400px" />
</td>
</tr>
<tr>
<td width="130">Verified:</td>
<td>
<asp:CheckBox ID="verifiedCheck" runat="server" />
</td>
</tr>
<tr>
<td width="130">Completed:</td>
<td>
<asp:CheckBox ID="completedCheck" runat="server" />
</td>
</tr>
<tr>
<td width="130">Canceled:</td>
<td>
<asp:CheckBox ID="canceledCheck" runat="server" />
</td>
</tr>
<tr>
<td width="130">Comments:</td>
<td>
<asp:TextBox ID="commentsTextBox" runat="server" Width="400px" />
</td>
</tr>
<tr>
<td width="130">Customer Name:</td>
<td>
<asp:TextBox ID="customerNameTextBox" runat="server" Width="400px" />
</td>
</tr>
<tr>
<td width="130">Shipping Address:</td>
<td>
<asp:TextBox ID="shippingAddressTextBox" runat="server" Width="400px" />
</td>
</tr>
<tr>
<td width="130">Customer Email:</td>
<td>
<asp:TextBox ID="customerEmailTextBox" runat="server" Width="400px" />
</td>
</tr>
</table>
<br />
<asp:Button ID="editButton" runat="server" CssClass="SmallButtonText"
Text="Edit" Width="100px" />
<asp:Button ID="updateButton" runat="server" CssClass="SmallButtonText"
Text="Update" Width="100px" />
<asp:Button ID="cancelButton" runat="server" CssClass="SmallButtonText"
Text="Cancel" Width="100px" /><br />
<asp:Button ID="markVerifiedButton" runat="server" CssClass="SmallButtonText"
Text="Mark Order as Verified" Width="310px" /><br />
<asp:Button ID="markCompletedButton" runat="server" CssClass="SmallButtonText"
Text="Mark Order as Completed" Width="310px" /><br />
<asp:Button ID="markCanceledButton" runat="server" CssClass="SmallButtonText"
Text="Mark Order as Canceled" Width="310px" /><br />
<br />
<asp:Label ID="Label13" runat="server" CssClass="AdminPageText"
Text="The order contains these items:" />
<br />
<asp:GridView ID="grid" runat="server" AutoGenerateColumns="False"
BackColor="White" Width="100%">
<Columns>
<asp:BoundField DataField="ProductID" HeaderText="Product ID"
ReadOnly="True" SortExpression="ProductID" />
<asp:BoundField DataField="ProductName" HeaderText="Product Name"
ReadOnly="True" SortExpression="ProductName" />
<asp:BoundField DataField="Quantity" HeaderText="Quantity"
ReadOnly="True" SortExpression="Quantity" />
<asp:BoundField DataField="UnitCost" HeaderText="Unit Cost"
ReadOnly="True" SortExpression="UnitCost" />
<asp:BoundField DataField="Subtotal" HeaderText="Subtotal"
ReadOnly="True" SortExpression="Subtotal" />
</Columns>
</asp:GridView>
3. Start writing the code-behind logic of OrderDetailsAdmin.ascx by adding a new field named editMode, “transforming” the Page_Load method to Page_PreRender, and adding some code to it:
public partial class OrderDetailsAdmin : System.Web.UI.UserControl {
// edit mode by default is false private bool editMode = false;
// set up the form
protected void Page_PreRender(object sender, EventArgs e) {
// check if we must display order details if (Session["AdminOrderID"] != null)
{
// fill constituent controls with data PopulateControls();
// set edit mode SetEditMode(editMode);
} else // Hide
this.Visible = false;
} }
Note the use of Session["AdminOrderID"]—this is set in OrdersAdmin.aspx, when the admin- istrator selects an order from the list. The OrderDetailsAdmin.ascx reads this value to find out the ID of the order it needs to display details for. In the Page_PreRender function, you use two additional methods: PopulateControls, which populates all the controls on the form with data, and SetEditMode, which disables or enables the text boxes and check boxes for editing.
4. Add PopulateControls just after Page_PreRender. This method gets the order information into an OrderInfo object, which was especially created for this purpose, by calling the GetInfo method of the OrdersAccess class. Using the information from that object, the method fills the constituent controls with data. At the end, you call OrdersAccess.GetDetails, which returns the products in the specified order.
// populate the form with data private void PopulateControls() {
// obtain order ID from the session
string orderId = Session["AdminOrderID"].ToString();
// obtain order info
OrderInfo orderInfo = OrdersAccess.GetInfo(orderId);
// populate labels and text boxes with order info orderIdLabel.Text = "Displaying Order #" + orderId;
totalAmountLabel.Text = String.Format("{0:c}", orderInfo.TotalAmount);
dateCreatedTextBox.Text = orderInfo.DateCreated;
dateShippedTextBox.Text = orderInfo.DateShipped;
verifiedCheck.Checked = orderInfo.Verified;
completedCheck.Checked = orderInfo.Completed;
canceledCheck.Checked = orderInfo.Canceled;
commentsTextBox.Text = orderInfo.Comments;
customerNameTextBox.Text = orderInfo.CustomerName;
shippingAddressTextBox.Text = orderInfo.ShippingAddress;
customerEmailTextBox.Text = orderInfo.CustomerEmail;
// by default the Edit button is enabled, and the // Update and Cancel buttons are disabled
editButton.Enabled = true;
updateButton.Enabled = false;
cancelButton.Enabled = false;
// Decide which one of the other three buttons // should be enabled and which should be disabled if (canceledCheck.Checked || completedCheck.Checked) {
// if the order was canceled or completed ...
markVerifiedButton.Enabled = false;
markCompletedButton.Enabled = false;
markCanceledButton.Enabled = false;
}
else if (verifiedCheck.Checked) {
// if the order was not canceled but is verified ...
markVerifiedButton.Enabled = false;
markCompletedButton.Enabled = true;
markCanceledButton.Enabled = true;
} else {
// if the order was not canceled and is not verified ...
markVerifiedButton.Enabled = true;
markCompletedButton.Enabled = false;
markCanceledButton.Enabled = true;
}
// fill the data grid with order details
grid.DataSource = OrdersAccess.GetDetails(orderId);
grid.DataBind();
}
5. Write the SetEditMode method now, which enables or disables edit mode for the information text boxes.
// enable or disable edit mode private void SetEditMode(bool enable) {
dateCreatedTextBox.Enabled = enable;
dateShippedTextBox.Enabled = enable;
verifiedCheck.Enabled = enable;
completedCheck.Enabled = enable;
canceledCheck.Enabled = enable;
commentsTextBox.Enabled = enable;
customerNameTextBox.Enabled = enable;
shippingAddressTextBox.Enabled = enable;
customerEmailTextBox.Enabled = enable;
editButton.Enabled = !enable;
updateButton.Enabled = enable;
cancelButton.Enabled = enable;
}
This method receives a bool parameter that specifies whether you enter or exit edit mode. When entering edit mode, all text boxes and the Update and Cancel buttons become enabled, while the Edit button is disabled. The reverse happens when exiting edit mode (this happens when one of the Cancel and Update buttons is clicked).
6. Now, start implementing the code that allows the administrator to edit order information. To make your life easier, first double-click each of the buttons (Edit, Cancel, Update) in Design View to let Visual Studio generate the signatures of the event handlers. Here’s the code:
// enter edit mode
protected void editButton_Click(object sender, EventArgs e) {
editMode = true;
}
// cancel edit mode
protected void cancelButton_Click(object sender, EventArgs e) {
// don't need to do anything, editMode will be set to false by default }
// update order information
protected void updateButton_Click(object sender, EventArgs e) {
// Store the new order details in an OrderInfo object OrderInfo orderInfo = new OrderInfo();
string orderId = Session["AdminOrderID"].ToString();
orderInfo.OrderID = Int32.Parse(orderId);
orderInfo.DateCreated = dateCreatedTextBox.Text;
orderInfo.DateShipped = dateShippedTextBox.Text;
orderInfo.Verified = verifiedCheck.Checked;
orderInfo.Completed = completedCheck.Checked;
orderInfo.Canceled = canceledCheck.Checked;
orderInfo.Comments = commentsTextBox.Text;
orderInfo.CustomerName = customerNameTextBox.Text;
orderInfo.ShippingAddress = shippingAddressTextBox.Text;
orderInfo.CustomerEmail = customerEmailTextBox.Text;
// try to update the order try
{
// Update the order
OrdersAccess.Update(orderInfo);
}
catch (Exception ex) {
// In case of an error, we simply ignore it }
// Exit edit mode SetEditMode(false);
// Update the form PopulateControls();
}
■Note Here we didn’t implement a mechanism to let the administrator know whether the update was successful or failed—if something happens, we just ignore the error. You’ve learned various error-handling techniques in this and previous chapters, and you can choose to implement whichever technique you think is best for your application.
7. Do the same for the last three buttons:
// mark order as verified
protected void markVerifiedButton_Click(object sender, EventArgs e) {
// obtain the order ID from the session
string orderId = Session["AdminOrderID"].ToString();
// mark order as verified
OrdersAccess.MarkVerified(orderId);
// update the form PopulateControls();
}