Managed C++ and .NET Development: Visual Studio .NET 2003 Edition

You have covered the basics of Web applications and Web Forms, how to build a Web application within Visual Studio .NET for a Managed C++ codebehind, and how to set it up for debugging. Now you'll go ahead and make a few Web Forms that actually do something. To do this you need to add, as discussed briefly previously, what ASP.NET calls Web Form controls.

Web Form controls provide you the ability to build a Web interface in a modular fashion. Each Web Form control provides a specific type of input and/or output functionality to your Web Form. For example, there are Web Form controls to place a label or image on the screen, click a button, display and input text data, and select a data item from a list.

All Web Form controls inherit from the WebControl class, which provides a number of standard methods and properties. Each Web Form control has a few methods and properties of its own that make it unique. Also, all Web Form controls have events for which you can create handlers. You can find all controls provided by ASP.NET within the System::Web::UI::WebControls namespace.

Let's take a look at several of the Web Form controls provided by ASP.NET, starting with one of the easiest: Label.

Note

The following descriptions of the common properties used for each control assume that the Web control will be sent to a Cascading Style Sheets, level 1 (CSS1)-compliant browser. If ASP.NET determines that the browser is not CSS1 compliant, it will send HTML that best approximates these properties' functionality.

Note

All properties that update the CSS1 style for a control can be overruled by the ! IMPORTANT CSS1 property.

Label

This useful, yet extremely simple, control allows you to display text at a set location on the page. Unlike static text, which you simply code directly in the .aspx file, you can dynamically change the text that is displayed using the Text property. A neat feature of the Label is that you can embed HTML tags within the text that you add. This makes the Label control extremely flexible.

The properties that you will most likely use with the Label control are as follows:

Color.aspx (see Listing 14-7) and Color.aspx.h (see Listing 14-8) are the GUI design and codebehind showing the Label control in action. The Web Form displays an italicized string with a random foreground and background color. To make things more interesting, I added the <meta http-equiv="Refresh" content="1"> tag to cause the form to update with random colors every second. Also, just to show that it can be done, I boldfaced a portion of the displayed string.

Listing 14-7: The ASP.NET GUI Design File Color.aspx

<%@ Assembly Name="WebForms" %> <%@ Page Inherits="WebForms.ColorfulForm" %> <html> <head> <title>Changing Colors</title> <meta http-equiv="Refresh" content="1"> </head> <body> <form method="post" runat="server"> <asp:Label runat="server"></asp:Label> </form> </body> </html>

Listing 14-8: The Codebehind Color.aspx.h

using namespace System; using namespace System::Drawing; using namespace System::Web::UI; using namespace System::Web::UI::WebControls; namespace WebForms { public __gc class ColorfulForm : public Page { protected: Label *Label; protected: void OnLoad(EventArgs *e) { Random *r = new Random(); Label->ForeColor = Color::FromArgb(r->Next(255),r->Next(255),r->Next(255)); Label->BackColor = Color::FromArgb(r->Next(255),r->Next(255),r->Next(255)); Label->Text = S"Let's randomly change <b>colors</b> until you get sick " S"of watching it"; Label->Font->Italic = true; Page::OnLoad(e); } }; }

As you can see, the .aspx file is very simple—it's just an empty <asp:Label> control. The real work of the Web Form happens in the codebehind (see Listing 14-8).

In this example, you don't have any event to delegate, so you can safely omit the overriding of OnInit() method. The important overridable method in this example is the OnLoad() method. This method gets executed every time Load event is triggered. Another way of looking at it is that the OnLoad() method will be executed whenever the client browser page is about to be loaded.

Something you should note is that the OnLoad() method is executed before any other Web control events. For example, when you click a button on a control, the OnLoad() method is executed and then the button event. Because this is the case, you need to make sure to code only what you want executed every time the Web Form is loaded within the OnLoad() method.

There is one exception to this. The Page class provides an IsPostBack property that can be checked to see if this is the first time the OnLoad() method has been called for the Web Form for this session. You will look at IsPostBack in more detail later in the chapter.

In the preceding example, you want the same code executed on every Load event, so the OnLoad() method doesn't need to use the IsPostBack property. In this case, the OnLoad() method simply creates a random number generator class and then populates the ForeColor and BackColor properties using the Color class's static FromArgb() method. (You examine this method in detail in Chapter 11.) Next, you set the Italic property within the Font property to true. Finally, you call the base class's version of the OnLoad() method to make sure that any code in the base class's version of the OnLoad() method is also executed.

Figure 14-10 shows a "colorful" black-and-white still image of the Colorful Web Form.

Figure 14-10: The Colorful Web Form

Image

Sooner or later you are going to want to add something other than text to your Web Form. The Image control allows you to display images on the page. Unlike the static <img> tag, you can dynamically change the image that is being displayed by changing the ImageUrl property. In addition, it is possible to do things such as resize the image and change its Web Form alignment.

The properties that you will most likely use with the Image control are as follows:

Happy.aspx (see Listing 14-9) and Happy.aspx.h (see Listing 14-10) are the GUI design and codebehind showing the Image control in action. The Web Form displays a happy face image expanding or contracting 10 pixels at every Web Form submit.

Listing 14-9: The ASP.NET GUI Design File Happy.aspx

<%@ Assembly Name="WebForms" %> <%@ Page Inherits="WebForms.Happy" %> <HTML> <HEAD> <title>Happy Face</title> </HEAD> <body> <form method="post" runat="server"> <P> <asp:image runat="server" ImageUrl="images/Happy.GIF" ImageAlign="Left"> </asp:image> </P> </form> </body> </HTML> <script language="JavaScript"> Happy.submit(); </script>

Listing 14-10: The Codebehind Color.aspx.h

using namespace System; using namespace System::Web::UI; using namespace System::Web::UI::WebControls; namespace WebForms { public __gc class Happy : public Page { protected: WebControls::Image *imgHappy; void OnLoad(EventArgs *e) { if (!IsPostBack) { // Create a session object the first time Web Form is loaded Session->Item[S"cSize"] = __box(32); } // Copy the session object to local variable for easy access Int32 cSize = *dynamic_cast<Int32*>(Session->Item[S"cSize"]); if (cSize % 2 == 1) { cSize -= 10; if (cSize < 32) cSize = 32; } else { cSize += 10; if (cSize > 400) cSize -= 1; } imgHappy->Width = Unit::Pixel(cSize); imgHappy->Height = Unit::Pixel(cSize); // Update the session object for next post back Session->Item[S"cSize"] = __box(cSize); Page::OnLoad(e); } }; }

This .aspx file demonstrates a simple little trick that you can do using JavaScript. When JavaScript commands are found outside of a function within HTML code, they get executed immediately when encountered by the browser's interpreter. In the preceding example, you applied this trick by adding the following script after all the HTML code:

<script language="JavaScript"> Happy.submit(); </script>

What this does is force the Web Form to be immediately submitted after the image is rendered to the client browser. You will see a more usable example of this trick in the "Tables" section later in this chapter when I show you how to update the browser status bar.

Like the previous example, all the code logic of the codebehind falls within the OnLoad() method. The main thing to note about this example is the use of a Session object:

if (!IsPostBack) { // Create a session object the first time Web Form is loaded Session->Item[S"cSize"] = __box(32); } // Copy the session object to local variable for easy access Int32 cSize = *dynamic_cast<Int32*>(Session->Item[S"cSize"]); //...Use the session object // Update the session object for next post back Session->Item[S"cSize"] = __box(cSize);

A Session object is extremely handy and allows you to store data between one page load and another within a single session. It is implemented using a Hashtable collection of key/value pairs. The basic syntax to create and update a Session object is this:

Session->Item[S"String key"] = (Object*) value;

To get access to the Session object, you use the following syntax:

Object *value = dynamic_cast<Object*>(Session->Item[S"String key"]);

The codebehind, once you get past the Session object logic, is fairly straightforward. First, the OnLoad() method uses the IsPostBack variable to see if this is the first page load and if it loads the Session object. Next, it loads a local version of the Session object for faster and easier access to its value. From there, it goes into the main logic of the codebehind, checking to see if the cSize is even or odd. If it is even, the happy face is expanding. If it is odd, the happy face is contracting. Two checks are made to see if you have reached either the minimum or maximum size of the happy face and, if so, the expansion/contraction process is reversed. The width and height of the happy face image are then updated. Finally, the cSize is placed back into the Session object for the next time the OnLoad() method for this particular session is called.

Figure 14-11 shows the happy face image as it starts to contract within the Happy Web Form.

Figure 14-11: The Happy Web Form

TextBox

I can almost guarantee that you will need to get some form of textual information from the users of your Web site. The TextBox control is the only Web Form control provided by ASP.NET that lets a user enter text.

Most of the properties that you will use with the TextBox will only be implemented at design time. For example, the TextMode property determines if the text box is SingleLine (the default), MultiLine, or Password. The width of the TextBox is specified by its Columns property. If the TextMode of the TextBox is set to MultiLine, then its height is specified by the Rows property. Under normal conditions, none of these properties would be changed at runtime. (Not that this isn't possible.)

An important property that you will normally leave alone but that occasionally comes in handy is the EnableViewState property. This Boolean property specifies if the state of the text is retained or, in other words, it specifies whether the text within the control remains after a trip from the client to the server and back.

The properties that you will most likely use with the TextBox control are as follows:

ChangeColor.aspx (see Listing 14-11) and ChangeColor.aspx.h (see Listing 14-12) are the GUI design and codebehind showing the TextBox control in action. The Web Form displays a TextBox, which requests the user to enter two colors separated by a comma. The first color is the foreground or text color and the second color is the background color of the TextBox. If you enter an invalid color, then the default color is displayed.

Listing 14-11: The ASP.NET GUI Design File ChangeColor.aspx

<%@ Assembly Name="WebForms" %> <%@ Page Inherits="WebForms.ChangeColor" %> <HTML> <HEAD> <title>Change Color</title> </HEAD> <body> <form method="post" runat="server"> Enter "foreground color", "background color" then press return: <asp:TextBox runat="server" Columns="30" AutoPostBack="True"> </asp:TextBox> </form> </body> </HTML>

Listing 14-12: The Codebehind ChangeColor.aspx.h

using namespace System; using namespace System::Drawing; using namespace System::Web::UI; using namespace System::Web::UI::WebControls; namespace WebForms { public __gc class ChangeColor : public Page { protected: TextBox *tbChanger; protected: void OnInit(EventArgs *e) { tbChanger->TextChanged += new EventHandler(this, tbChanger_TextChanged); Page::OnInit(e); } private: void tbChanger_TextChanged(Object *sender, EventArgs *e) { Char AComma[] = {','}; String *incolors[]; // parse out the colors incolors = tbChanger->Text->Split(AComma); // change the foreground and background tbChanger->ForeColor = Color::FromName(incolors[0]); if (incolors->Length > 1) tbChanger->BackColor = Color::FromName(incolors[1]); } }; }

There is not much here of interest, except for the use of the AutoPostBack property within the TextBox. This property causes a post back whenever changes are made to the control. Normally, this post back is triggered when you leave the control by pressing the Tab key or by clicking another control but, because this is the only control on the Web Form, pressing the Enter key also works.

Because the preceding example was only one control, you could have written the codebehind using an OnLoad() method like you did in the previous example. It would even have taken less code. This method makes more sense as you are capturing the change of the text in the TextBox, so why not use the correct event?

By the way, the if statement checking the number of colors entered into the TextBox avoids an exception being thrown. I found this out the hard way.

Figure 14-12 shows in black-and-white the TextBox with a blue background and yellow text. (Guess you will have to take my word on it.)

Figure 14-12: The ChangeColor form

Buttons and Hyperlinks

Entering text definitely has its place, but a mouse-click response is a much preferred way of providing input from the user's perspective. It's quick, simple, and the user's hands don't have to leave the mouse. Of course, you can't provide mouse-click responses for everything but, when you do, ASP.NET provides four buttons, a hyperlink, and a button that looks like a hyperlink from which you can choose:

Other than the Enable and Visible properties, in most cases, you will not be dealing with the properties of a button in the codebehind. Instead, you will configure the button in the design code and then simply handle the Click event of the button.

As you can probably guess, the Enable property specifies whether the button is or is not accessible to the user but is still displayed on the client browser. The Visible property makes the button disappear. In fact, if a button is invisible, the button does not even get sent to the client browser.

The CheckBox and RadioButton are a little different from the other buttons in that you will also need to work with the Checked property. The Checked property specifies whether the control has been selected or not.

Buttons.aspx (see Listing 14-13) and Buttons.aspx.h (see Listing 14-14) are the GUI design and codebehind showing buttons and hyperlinks in action. The Web Form looks a lot more complex than it is. It is just a four-cell table grouped by the button type. Each cell provides three buttons to select the three Web Forms created previously in the chapter.

Listing 14-13: The ASP.NET GUI Design File Buttons.aspx

<%@ Assembly Name="WebForms" %> <%@ Page Inherits="WebForms.Buttons" %> <HTML> <HEAD> <title>Buttons</title> </HEAD> <body> <form method="post" runat="server"> <TABLE cellSpacing="4" cellPadding="4" border="2"> <TR> <TD> <asp:radiobutton runat="server" AutoPostBack="True" Text="Colorful" GroupName="PageGroup"> </asp:radiobutton> <P> <asp:radiobutton runat="server" AutoPostBack="True" Text="Happy Face" GroupName="PageGroup"> </asp:radiobutton> <P> <asp:radiobutton runat="server" AutoPostBack="True" Text="TextBox Color" GroupName="PageGroup"> </asp:radiobutton> </TD> <TD> <asp:checkbox runat="server" Text="Colorful"> </asp:checkbox> <P> <asp:checkbox runat="server" Text="Happy Face"> </asp:checkbox> <P> <asp:checkbox runat="server" Text="TextBox Color"> </asp:checkbox> <P> <asp:button runat="server" Text="Go to first checked box"> </asp:button> </TD> </TR> <TR> <TD> <asp:button runat="server" Text="Colorful" ForeColor="Navy" BorderColor="Purple" BackColor="PaleGreen"> </asp:button> <P> <asp:imagebutton runat="server" Border ImageUrl="images/Happy.GIF"> </asp:imagebutton> <P> <asp:button runat="server" Text="TextBox Color"> </asp:button> </TD> <TD> <asp:hyperlink runat="server" NavigateUrl="Color.aspx"> Colorful </asp:hyperlink> <P> <asp:HyperLink runat="server" NavigateUrl="Happy.aspx" ImageUrl="images/Happy.GIF"> Happy Face </asp:HyperLink> <P> <asp:LinkButton runat="server"> TextBox Color </asp:LinkButton> </TD> </TR> </TABLE> </form> </body> </HTML>

Listing 14-14: The Codebehind Buttons.aspx.h

using namespace System; using namespace System::Drawing; using namespace System::Web::UI; using namespace System::Web::UI::WebControls; namespace WebForms { public __gc class Buttons : public Page { protected: // Row 1 Column 1 - Controls RadioButton *rbColorful; RadioButton *rbHappy; RadioButton *rbChange; // Row 1 Column 2 - Controls CheckBox *cbColorful; CheckBox *cbHappy; CheckBox *cbChange; Button *bnCheckBoxes; // Row 2 Column 1 - Controls Button *bnColorful; ImageButton *ibnHappy; Button *bnChange; // Row 2 Column 2 - Control LinkButton *lbnChange; void OnInit(EventArgs *e) { // Row 1 Column 1 - Event Delegations rbColorful->CheckedChanged += new EventHandler(this, RB_ChkChanged); rbHappy->CheckedChanged += new EventHandler(this, RB_ChkChanged); rbChange->CheckedChanged += new EventHandler(this, RB_ChkChanged); // Row 1 Column 2 - Event Delegation bnCheckBoxes->Click += new EventHandler(this, bnCheckBoxes_Click); // Row 2 Column 1 - Event Delegations bnColorful->Click += new EventHandler(this, bnColorful_Click); ibnHappy->Click += new ImageClickEventHandler(this, ibnHappy_Click); bnChange->Click += new EventHandler(this, bnChange_Click); // Row 2 Column 2 - Event Delegation lbnChange->Click += new EventHandler(this, lbnChange_Click); Page::OnInit(e); } private: // Row 1 Column 1 - Event Handler void RB_ChkChanged(Object *sender, EventArgs *e) { if (rbColorful->Checked) Response->Redirect(S"Color.aspx"); else if (rbHappy->Checked) Response->Redirect(S"Happy.aspx"); else if (rbChange->Checked) Response->Redirect(S"ChangeColor.aspx"); } // Row 1 Column 2 - Event Handler void bnCheckBoxes_Click(Object *sender, EventArgs *e) { if (cbColorful->Checked) Response->Redirect(S"Color.aspx"); else if (cbHappy->Checked) Response->Redirect(S"Happy.aspx"); else if (cbChange->Checked) Response->Redirect(S"ChangeColor.aspx"); } // Row 2 Column 1 - Event Handlers void bnColorful_Click(Object *sender, EventArgs *e) { Response->Redirect(S"Color.aspx"); } void ibnHappy_Click(Object *sender, ImageClickEventArgs *e) { Response->Redirect(S"Happy.aspx"); } void bnChange_Click(Object *sender, EventArgs *e) { Response->Redirect(S"ChangeColor.aspx"); } // Row 2 Column 2 - Event Handler void lbnChange_Click(Object *sender, EventArgs *e) { Response->Redirect(S"ChangeColor.aspx"); } }; }

There is no special coding in the preceding design code. You might want to notice the use of standard HTML table tags. Later in this chapter, you will see Table control, which is a lot different coding-wise but very similar functionality-wise.

The Buttons codebehind has a few things worth noting. The first is that you can have multiple events handled by the same event handler. In the preceding example, you see this done with the RadioButton control's CheckedChanged events (which, incidentally, you also set for AutoPostBack in each RadioButton):

rbColorful->CheckedChanged += new EventHandler(this,RadioButton_CheckedChanged); rbHappy->CheckedChanged += new EventHandler(this, RadioButton_CheckedChanged); rbChange->CheckedChanged += new EventHandler(this, RadioButton_CheckedChanged);

You might also note that only the handler for the control that actually gets clicked is triggered even though the name of the event seems to imply that both the radio button that was checked and the radio button that became unchecked should also be triggered (as it changed also). Because of this, it would also have been possible to code this example by checking which control sent the event and then processing for that event. This makes the checked property unneeded:

void RadioButton_CheckedChanged(Object *sender, EventArgs *e) { if (sender == rbColorful) Response->Redirect(S"Colorful.aspx"); else if (sender == rbHappy) Response->Redirect(S"Happy.aspx"); else if (sender == rbChange) Response->Redirect(S"ChangeColor.aspx"); }

Another thing that might cause you a few minutes of research (although after reading this, this should not be the case) is that ImageButtons differ from all the other button Click events, in that they use a different event handler. They use ImageClickEventHandler instead of the more standard EventHandler:

ibnHappy->Click += new ImageClickEventHandler(this, ibnHappy_Click);

Probably the most important thing shown in the preceding example is how to programmatically jump to a new Web page using the Redirect() method within the Response property of the Page class:

Response->Redirect(S"Colorful.aspx");

The preceding example shows how to jump to a local Web Form. To jump to a Web Form on a different server, you need to use the full URL, starting with http://:

Response->Redirect(S"http://www.contentmgr.com/default.aspx");

Figure 14-13 shows an assortment of buttons from which you can select the previous examples.

Figure 14-13: The Buttons form

Lists

A list control is really nothing more than a control that displays a list of items in the client browser. Many of the list controls provided by ASP.NET allow for user input, but that is not a requirement for it to be a list control. ASP.NET provides seven list controls to choose from:

In the preceding list, it was shown that list controls display bound data. Basically, bound data are collections that support the IEnumerable, ICollection, or IListSource interface. In other words, you can display the collections discussed in Chapter 7 and the DataView, DataSet, and DataReader objects discussed in Chapter 12 using list controls.

Two members that all list controls have in common are the DataSource property and the DataBind() method. To dynamically create a list requires you to use both members together. The DataSource property associates a bound data source with the list control. The DataBind() method then binds the data source to the control. A common mistake is to forget to call DataBind(). You will know when you have done this because you will get no data being displayed in the list control for which you have set the DataSource property.

To determine which item was selected, you will probably use the SelectedItem property. You can use the SelectedIndex property in conjunction with the Items property but, as you can see here, using SelectedItem is much easier:

String *val1 = listBox->SelectedItem->Value; String *val2 = listBox->Items->Item[listBox->SelectedIndex]->Value;

To set an item in a list control as selected, you use the SelectedIndex property:

listBox->SelectedIndex = 3; // remember items start at an index of 0

Remember, the Repeater control doesn't allow for item selection, therefore it doesn't define either the SelectedItem property or the SelectedIndex property.

Lists.aspx (see Listing 14-15) and Lists.aspx.h (see Listing 14-16) are the GUI design and codebehind showing a few list controls in action. You might want to pay attention to this example as it shows how to extract the tables out of an OLE DB database and place them in a table for selection. Once the table is selected, a DataGrid of the table displays all the content of the table. Personally, I think this example may come in handy in your future. I also threw in a drop-down control that changes the background color of the DataGrid control to show how to manually create a list control.

Listing 14-15: The ASP.NET GUI Design File Lists.aspx

<%@ Assembly Name="WebForms" %> <%@ Page Inherits="WebForms.Lists" %> <HTML> <HEAD> <title>Lists</title> </HEAD> <body> <form method="post" runat="server"> <P> <asp:ListBox runat="server" AutoPostBack="True"> </asp:ListBox> </P> <P> <asp:DataGrid runat="server"> </asp:DataGrid> </P> <P> <asp:DropDownList runat="server" Enabled="False" AutoPostBack="True"> <asp:ListItem Value="white">Select Background Color</asp:ListItem> </asp:DropDownList> </P> </form> </body> </HTML>

Listing 14-16: The Codebehind Lists.aspx.h

using namespace System; using namespace System::Data; using namespace System::Data::OleDb; using namespace System::Drawing; using namespace System::Web::UI; using namespace System::Web::UI::WebControls; namespace WebForms { public __gc class Lists : public Page { protected: ListBox *selListBox; DataGrid *dataGrid; DropDownList *colorList; void OnLoad(EventArgs *e) { OleDbConnection *con; try { #ifdef OLEDBAuth // SOL Server authentication String *conStr = S"Provider=SQLOLEDB.1;" S"User ID=sa; Password=;" S"Data Source=(local); Initial Catalog=DCV_DB;"; #else // Windows Integrated Security String *conStr = S"Provider=SQLOLEDB.1;" S"Persist Security Info=False; Integrated Security=SSPI;" S"Data Source=(local); Initial Catalog=DCV_DB;"; #endif con = new OleDbConnection(conStr); con->Open(); if (!IsPostBack) { // Set up database table list box Object *restrict[] = {0, 0, 0, S"TABLE"}; DataTable *dt = con->GetOleDbSchemaTable(OleDbSchemaGuid::Tables, restrict); selListBox->DataSource = dt->DefaultView; selListBox->DataTextField = S"TABLE_NAME"; selListBox->DataBind(); // Set up Background color list box colorList->Items->Add(S"Yellow"); colorList->Items->Add(new ListItem(S"Green",S"LightGreen")); colorList->Items->Add(S"Red"); } else { // Build data grid from selected database table String *selectedTable = selListBox->SelectedItem->Value; String *Cmd = String::Concat(S"SELECT * FROM ", selectedTable); OleDbDataAdapter *dAdapt = new OleDbDataAdapter(Cmd, con); DataSet *dSet = new DataSet(); dAdapt->Fill(dSet); dataGrid->DataSource = dSet; dataGrid->DataBind(); dataGrid->BackColor = Color::FromName(colorList->SelectedItem->Value); // enable background color list box colorList->Enabled = true; } } catch(Exception *exp) { // Do Exception handling throw exp; } __finally { // Close down the database con->Close(); } } }; }

There's nothing new in this design file other than it disables the drop-down list when the Web Form is first created. It doesn't make sense to have it enabled until there's a DataGrid for which to change the background.

This codebehind could have been written so that processing was handled within SelectedIndexChange event handlers, but as I started coding, I realized that the same code was being executed no matter which control event was triggered. The only time this differed was on the initial Web Form generated. In other words, the same code was always run on every post back—only the initial post did something different. Because this was the case, it was possible to write all the logic within the OnLoad() method, as seen previously, because the OnLoad() method is called for every post back.

The first thing the OnLoad() method does is open up the database. Then if this is the first time the Web Form is loaded, it creates two list controls. The first is a ListBox of all the tables within the database. The second is a DropDownList of all the colors that the DataGrid background can be set to.

To get all the tables in a database, you need to use the GetOleDbSchemaTable() method. The first parameter you pass is an OleDbSchemaGuid value that specifies the schema table to return. The second parameter is an array of restriction values. To get the tables in the database, you need to first pass OleDbSchemaGuid::Tables, which specifies that you want the schema table of all the tables in the database. Then you restrict the fourth column to "TABLE". The valid restrictions for the fourth column are "ALIAS", "TABLE", "SYNONYM", "SYSTEM TABLE", "VIEW", "GLOBAL TEMPORARY", "LOCAL TEMPORARY", and "SYSTEM VIEW".

Object *restrict[] = {0, 0, 0, S"TABLE"}; DataTable *dt = con->GetOleDbSchemaTable(OleDbSchemaGuid::Tables, restrict);

When the GetOleDbSchemaTable() method returns, you have a DataTable containing information about the tables in the database. Now all you have to do is place the column in the DataTable containing the table name in the ListBox. You do this by first making the default view of the DataTable the data source of the ListBox and then selecting the TABLE_NAME column to be used as the item to be displayed in the ListBox using the DataTextField property. Don't forget to call the DataBind() method:

selListBox->DataSource = dt->DefaultView; selListBox->DataTextField = S"TABLE_NAME"; selListBox->DataBind();

To build a list control dynamically, you use the Add() method found within the Items property. Then you can either add a ListItem object, which allows you to specify different Text and Value properties to the list control, or add a String object, which sets the Text and Value to the same value (the passed String).

colorList->Items->Add(new ListItem(S"Green",S"LightGreen")); colorList->Items->Add(S"Red");

By the way, it is also possible to Insert(), Remove(), and Clear() ListItems from a list control.

On a post back, the OnLoad() method does not need to load the Tables or Colors list control because the Web Form will retain the list control information and state between post backs. Instead, what needs to be built is the DataGrid of the contents of the selected Table. You do this by assigning the DataSet of the Table's contents to the DataGrid and then calling DataBind(). You saw how to create a DataSet in Chapter 12.

String *selectedTable = selListBox->SelectedItem->Value; String *Cmd = String::Concat(S"SELECT * FROM ", selectedTable); OleDbDataAdapter *dAdapt = new OleDbDataAdapter(Cmd, con); DataSet *dSet = new DataSet(); dAdapt->Fill(dSet); dataGrid->DataSource = dSet; dataGrid->DataBind();

You grab the background color to display out of the color drop-down list. Notice that the first time this is called, the drop-down list is not enabled and its value is White, even though the text says "Select Background Color". Once you have created a DataGrid, you can then enable the color drop-down list.

dataGrid->BackColor = Color::FromName(colorList->SelectedItem->Value); // enable background color list box colorList->Enabled = true;

Figure 14-14 shows the content of the Content database table, with a green background. (I know it looks gray to you, but it really is green—honest.)

Figure 14-14: The list form

Tables

You are probably very familiar with the HTML table tag. You might be wondering why you would need another table in the form of a control. The answer is primarily its ability to be dynamically maintained within ASP.NET. With the Table control, you have much more flexibility and control when it comes to dynamically changing the look and feel of the content, layout, and so forth of your tables. Ultimately, though, the HTML generated will be standard HTML table tags.

When you work with the Table control, you will be working primarily with three classes:

Unlike some of the other controls described previously, the Table control is designed to be used programmatically. Thus, you will be frequently working with the members of the Table control in the codebehind, instead of setting them once within the GUI design file.

Some of the more common properties of the Table control are as follows:

Like the Table control, you will be working frequently with TableRow control's properties. Many of the properties of the TableRow are the same as those of the Table control. Where they are the same, the TableRow control property overrules the Table control's property. Here are some of the more common TableRow controls:

Just like the other two table controls, you will be frequently using TableCell control properties—if you are creating tables, that is. There are also many common properties among all three table controls. The TableCell control property ultimately overrules all others. Here are some of the more common TableCell properties:

When you create tables using the Table control, you will be in essence coding the same steps every time. The basic steps to building a table using the Table control are as follows:

  1. Create a Table control via the GUI design file.

  2. Create a TableRow.

  3. Create a TableCell.

  4. Create a Web Form control.

  5. Place the control in the TableCell.

  6. Place the TableCell in the TableRow.

  7. Repeat steps 3 through 6 for each TableCell in the TableRow.

  8. Place the TableRow in the Table.

  9. Repeat steps 2 through 8 for each TableRow in the Table.

Caution

Programmatic changes made to a Table control are not persistent across post backs. Therefore, any changes you make to TableRows and/or TableCells need to be reconstructed after each post back. If you expect substantial changes, then you should use the Data List or DataGrid controls instead.

Tables.aspx (see Listing 14-17) and Tables.aspx.h (see Listing 14-18) are the GUI design and codebehind showing a table control in action. This Web Form displays all the files in the Web Form root directory along with a little information about each. Also, hidden in the code is how to update the status bar of the browser client.

Listing 14-17: The ASP.NET GUI Design File Tables.aspx

<%@ Assembly Name="WebForms" %> <%@ Page Inherits="WebForms.Tables" %> <HTML> <HEAD> <title>Tables</title> </HEAD> <body> <form method="post" runat="server"> <asp:Table runat="server" GridLines="Both"> <asp:TableRow> <asp:TableCell Text="Name"></asp:TableCell> <asp:TableCell Text="Created"></asp:TableCell> <asp:TableCell Text="Length"></asp:TableCell> <asp:TableCell Text="Attributes"></asp:TableCell> <asp:TableCell Text="Make Happy"> </asp:TableCell> </asp:TableRow> </asp:Table> </form> </body> </HTML>

Listing 14-18: The Codebehind Tables.aspx.h

using namespace System; using namespace System::IO; using namespace System::Web::UI; using namespace System::Web::UI::WebControls; namespace WebForms { public __gc class Tables : public System::Web::UI::Page { protected: // Create a Table control (Step 1) Table *FilesTable; void OnLoad(EventArgs *e) { LiteralControl *lit; TableCell *cell; String *files[] = Directory::GetFiles(Server->MapPath(".")); for (Int32 i = 0; i < files->Length; i++) { FileInfo *finfo = new FileInfo(files[i]); if (!finfo->Exists) continue; // Create a TableRow (Step 2) TableRow *row = new TableRow(); // Create a TableCell (Step 3) cell = new TableCell(); // Create a Web Form control (Step 4) // Creating a hyperlink control HyperLink *link = new HyperLink(); link->Text = finfo->Name; link->NavigateUrl = finfo->FullName; // Place the control in the TableCell (Step 5) cell->Controls->Add(link); // Place the TableCell in the TableRow (Step 6) row->Cells->Add(cell); // Repeat steps 3 through 6 (Step 7) // Creating a literal control lit = new LiteralControl( String::Concat(finfo->CreationTime.ToShortDateString(), S" ", finfo->CreationTime.ToLongTimeString())); cell = new TableCell(); cell->Controls->Add(lit); row->Cells->Add(cell); lit = new LiteralControl(finfo->Length.ToString()); cell = new TableCell(); cell->Controls->Add(lit); row->Cells->Add(cell); lit = new LiteralControl(__box(finfo->Attributes)->ToString()); cell = new TableCell(); cell->Controls->Add(lit); row->Cells->Add(cell); // Creating an image button control ImageButton *ibn = new ImageButton(); ibn->Command += new CommandEventHandler(this, btnHappy); ibn->ImageUrl = S"Images/Happy.gif"; ibn->CommandArgument = finfo->Name; cell = new TableCell(); cell->HorizontalAlign = HorizontalAlign::Center; cell->Controls->Add(ibn); row->Cells->Add(cell); // Place Row in Table (Step 8) FilesTable->Rows->Add(row); // Repeat steps 2 through 8 (Step 9) } } private: void btnHappy(Object *sender, CommandEventArgs *e) { this->Controls->Add(new LiteralControl(String::Concat( S"<script language=javascript>" S"window.status='The file ", e->CommandArgument, S" is now happy'" S"</script>" ))); } }; }

It would have been perfectly legitimate to have created the entire table in the codebehind, but because I know that the headings will always be the same, I thought it better to place them within the GUI design file. Notice that you can use CSS1 Style within the Table classes. I show only styles being done in the TableCell, but you can do it within the other controls as well.

The preceding example shows how you can place a hyperlink, three literals, and an image button within TableCells of a Table control.

Two things worth noting are the use of the CommandEventHandler and the updating of the browser status bar. The CommandEventHandler allows you to delegate an event and pass it an argument of your choosing. This process is done in two steps. First, you delegate an event handler to the Command event. Second, you place the argument you want to pass on the CommandArgument property. In the preceding example, I pass the name of the file that I want to make happy on the CommandArgument property. Now, when the event is triggered as you click the image button, the handler is called along with the parameter passed. I use this parameter to specify which file is happy on the browser's status bar.

If you recall, earlier in the chapter I pointed out that JavaScript, when placed out of a function call, gets called immediately when encountered. I use that to my advantage in the preceding example. What is happening here is that I am placing a string literal in the HTML stream that gets sent to the client browser. This literal happens to also be JavaScript code. So, when the browser interpreter is parsing the HTML, it encounters the JavaScript, runs it, and then continues on. In this case, the JavaScript calls the window.status method, which updates the status bar with the string assigned to it. Pretty neat, don't you think?

Figure 14-15 shows all the files in the Web Form's root directory as well as a happy file. Look at the status bar.

Figure 14-15: The Tables form

Категории