Editing DataGrid Controls

Editing In Place Using Templates

For columns belonging to the TemplateColumn class, you can define a special template that is applied when one cell of such a column is being edited. In previous examples, I built a templated column that displayed data obtained by merging the first and last names with the title of courtesy. When you need to edit the content of a heterogeneous column like that, provide a template that includes each input control. For example, you might want a drop-down list supplying all the possible values for the titleofcourtesy column. You also must use separate text boxes for the first and last names. The following code creates a possible edit template:

<edititemtemplate> <asp:dropdownlist runat="server" DataSource='<% # aTitlesOfCourtesy %>' /> <asp:textbox runat="server" width="80px" Text='<%# DataBinder.Eval(Container.DataItem, "firstname") %>' /> <br> <asp:textbox runat="server" width="140px" Text='<%# DataBinder.Eval(Container.DataItem, "lastname") %>' /> </edititemtemplate>

The presence of the EditItemTemplate template automatically makes a templated column editable. Figure 4-7 shows what the edit template looks like.

Figure 4-7

An editable templated column.

The drop-down list of titles is filled with the contents of a global array that is declared as follows:

String [] aTitleOfCourtesy = new String[4] {"Ms.", "Mr.", "Mrs.", "Dr."};

Other fields are rendered via text boxes initialized with data-bound contents. As you can see, using edit templates gives you the fullest flexibility because you can directly control any single step of the editing process: you can give the desired ID to the constituent controls, you can choose the controls that best suit your data, and you can place any ASP.NET validation control between the controls you choose. For example, you can use the ASP.NET class RegularExpression Validator to make sure that the text typed in a text box matches a given mask.

Working with Template Controls

Templates simplify the way you retrieve instances of the controls involved with the edit. You don t have to use the position-based approach examined earlier, because templates let you use the ID to identify controls. The use of the ID is not an option with edit templates it s an absolute necessity. Using unambiguous IDs is the only reliable way to retrieve a control during the edit phase.

Let s continue with our edit template example. The following code shows how to retrieve run-time values for the controls in the template of the Employee Name column:

TextBox txtFirstName = (TextBox) e.Item.FindControl("txtFirstName"); TextBox txtLastName = (TextBox) e.Item.FindControl("txtLastName"); DropDownList ddTitles = (DropDownList) e.Item.FindControl("ddTitles");

Notice that the templates are rooted in a separate naming container, which affects how FindControl works. First, you cannot call FindControl at the page or grid level. Instead you must resort to using the FindControl method of a templated DataGrid control item. Second, you cannot use any of those IDs in grid-level code. For example, using ddTitles directly in your code will result in a compile-time error. After you access all the template s controls, you can go on with the data source update as shown earlier.

Initializing Controls

Look carefully at Figure 4-7. You should notice an anomaly. The selected item in the drop-down list of possible titles does not match the correct title of the employee. In the figure, the record of employee Michael Suyama is being edited. The Title drop-down list defaults to Ms. instead of matching the current value. This matching issue introduces the more general topic of how to initialize the status of child controls in edit templates.

The first place I try to assign ad-hoc starting values to controls is in the EditCommand event (the user-defined procedure that enables in-place editing). The problem with this approach is that EditCommand is raised before the edit template is created. EditCommand is expected to set the EditItemIndex property, which causes the grid to draw in edit mode. To access controls at creation time, you should once again rely on the ItemCreated event.

public void ItemCreated(Object sender, DataGridItemEventArgs e) { ListItemType lit = e.Item.ItemType; if (lit == ListItemType.EditItem) { // Retrieve the drop-down list control to set up DropDownList ddTitles; ddTitles = (DropDownList) e.Item.FindControl("ddTitles"); // Get the item data as a DataRowView object DataRowView drv = (DataRowView) e.Item.DataItem; // Select the index that matches the title // in the current row if (drv != null) { String strTitle = drv["titleofcourtesy"].ToString(); int nIndex = Array.IndexOf(aTitleOfCourtesy, strTitle); ddTitles.SelectedIndex = nIndex; } } }

Make sure that the item type being created is EditItem. Then retrieve both the current instance of the drop-down list control and the data that is bound to the current grid item. This information depends on the kind of data you associated with the grid. For example, if you used a DataTable object, the item s data consists of a DataRowView object. Finally, you select the array element that matches the row value in the titleofcourtesy column and assign it to the SelectedIndex property of the drop-down list.

Stripping Off Unneeded Formatting Text

To make the cells of your data grid look more user-friendly, you can employ the DataFormatString attribute of BoundColumn, which will add style information that you cannot otherwise add. For example, suppose you want to pad a cell only horizontally. You must resort to the margin CSS attribute, which you have to apply directly to the content of the cell. You can t achieve this effect with any style property that the grid makes available. So you define DataFormatString as follows:

DataFormatString="<span style='margin-left:5; margin-right:5'>{0}</span>"

The value of the cell is wrapped by a <span> tag. The drawback is that when the user attempts to edit the column, the text box defaults to the whole HTML expression that constitutes the contents of the cell, as shown in this example:

<span style='margin-left:5;margin-right:5'>USA</span>

To work around this editing issue, you hook up the ItemCreated event, retrieve the text box control, and explicitly set the control to the contents of the data-bound field.

Adapting Layouts to Data

When you use a DataGrid control, you rarely display all the fields in the underlying table. When you edit a row, however, you might want to give users a chance to enter information in fields that are not in the grid s Columns collection. Templates give you this functionality. Just add some extra controls to one of the edit templates you define for a column.

The flexibility of templates also lets you adapt the edit layout to the data you are handling. For example, images and links aren t rendered through plain literal controls and require special rendering support from the grid. However, a database field might exist behind them, and to edit its contents, you use a template. Let me show how the process works for images.

Editing Columns That Point to Images

Suppose you have a table with a field named photo. The field does not contain pixels of an image; it contains only a relative path name. You can define an image column as you work by using the following template. Figure 4-8 shows the result of this code.

<asp:TemplateColumn runat="server" HeaderText="Photo"> <itemtemplate> <img runat="server" width="50" src='/books/2/368/1/html/2/<%# DataBinder.Eval(Container.DataItem, "photo") %>' /> </itemtemplate> </asp:TemplateColumn>

Figure 4-8

A DataGrid control that uses a templated column to show images.

To edit the underlying image path, use an edit template. All you have to do is adapt the grid s user interface to the data you display. You display image files by using pictures and edit the corresponding database column by using text boxes. Following is the code for an edit template that produces the results in Figure 4-9.

<edititemtemplate> <asp:textbox runat="server" Text='<%# DataBinder.Eval(Container.DataItem, "photo") %>' /> <hr> <img runat="server" width="100" src='/books/2/368/1/html/2/<%# DataBinder.Eval(Container.DataItem, "photo") %>' /> </edititemtemplate>

Figure 4-9

An edit template allows editing of an image s path name.

Sometimes when you use image-based columns, you won t have an image to display. When no image is found, you might want to resort to a different user interface. For example, you could employ a No picture available label instead of the image control. You could look at this example and decide that you just need dynamically loaded templates (discussed in Chapter 3), but this is a simple case and can be solved with a data-binding expression, as shown in the following code. Figure 4-10 shows the results of the code.

<itemtemplate> <img runat="server" width="50" visible='<%# IsFile(DataBinder.Eval(Container.DataItem, "photo")) %>' src='/books/2/368/1/html/2/<%# DataBinder.Eval(Container.DataItem, "photo") %>' /> <asp:label runat="server" text="<i><small>No picture available.</small></i>" visible='<%# !IsFile(DataBinder.Eval(Container.DataItem, "photo")) %>' /> </itemtemplate>

The template makes the <img> tag and the label mutually exclusive by hiding the one that does not apply.

private bool IsFile(String strFile) { return File.Exists(Server.MapPath(strFile)); }

Figure 4-10

When you don t have an image to display in an image-based column, you can use a data-binding expression to display a label instead.

Editing Link Columns

You handle the editing of columns containing a URL in almost the same way you handle the editing of image-based columns. If, for example, the information in a column containing a URL has to be considered read-only, you can use ad-hoc columns descending from the HyperLinkColumn class. If the contents of the field will be edited at run time, you are better off dropping ad-hoc columns in favor of templated columns. In this case, you can define a specific edit template.

<asp:TemplateColumn runat="server" HeaderText="URL"> <itemtemplate> <a runat="server" target="myframe" href='<%# DataBinder.Eval(Container.DataItem, "url") %>'> Go</a> </itemtemplate> <edititemtemplate> <asp:textbox runat="server" Text='<%# DataBinder.Eval(Container.DataItem, "url") %>' /> </edititemtemplate> </asp:TemplateColumn>

Editing Non-Displayed Columns

The layout for the edit template of a given column is rendered by ASP.NET code that you can devise and implement. You must use the ASP.NET controls that best fit the characteristics of the data being edited. You can also add extra controls to the template of a given column. These extra controls could, for example, refer to columns in the database that are not displayed in the normal view of the DataGrid control. You can take this approach even further and use the template s in-place editing features to build full-fledged interactive forms that users update with current data.

In Figure 4-8, you saw a DataGrid control featuring three templated columns Employee Name, Position, and Photo. Employee Name and Position are clearly made of more fields than the Photo column is. A user in edit mode, then, would reasonably expect to see several controls ready to receive her input. The Employees table actually has many more fields than are typically displayed. Some of these fields say, the notes and hiredate fields can also be edited in edit mode. For editing purposes, non-displayed columns must be hosted by other templated columns. The way you group editable columns is arbitrary and ruled only by your common sense for and sensitivity to user-friendliness.

The following edit template falls under the Employee Name column and accommodates the editing of four fields: titleofcourtesy, firstname, lastname, and hiredate. The hiredate column is edited through a special server-side control: the Calendar control.

<edititemtemplate> <asp:dropdownlist runat="server" DataSource='<% # aTitleOfCourtesy %>' /> <asp:textbox runat="server" width="80px" Text='<%# DataBinder.Eval(Container.DataItem, "firstname") %>' /> <br> <asp:textbox runat="server" width="140px" Text='<%# DataBinder.Eval(Container.DataItem, "lastname") %>' /> <hr> <asp:calendar runat="server" BackColor="white" ForeColor="black" Font-Size="9px" DayHeaderStyle-Font-Bold="True" VisibleDate='<%# DataBinder.Eval(Container.DataItem, "hiredate") %>' SelectedDate='<%# DataBinder.Eval(Container.DataItem, "hiredate") %>' /> </edititemtemplate>

note

The Calendar control requires you to set both VisibleDate and SelectedDate to the same DateTime value if you want a particular date to appear selected. The VisibleDate property ensures that a given date is visible in the displayed page of the calendar. The SelectedDate property draws the date using a special style to indicate the current selection.

The preceding code will generate a run-time error if the hiredate field is null. To avoid the null value, do the following:

VisibleDate='<%# IsDate( DataBinder.Eval(Container.DataItem, "hiredate")) %>' SelectedDate='<%# IsDate( DataBinder.Eval(Container.DataItem, "hiredate")) %>'

The function IsDate will simply check whether the passed object is null and, in our case, default to the current date.

private DateTime IsDate(Object o) { if (o is DBNull) return DateTime.Now; return Convert.ToDateTime(o); }

caution

The Calendar control originates a round-trip for each selection the user makes. Although this control is cool and powerful, for a better performance, you might also want to provide a plain text box so that the user can type in dates manually.

The code that follows illustrates an edit template for the Position column. It embeds a multiline text box control so that the user can edit the notes field.

<edititemtemplate> <asp:textbox runat="server" Text='<%# DataBinder.Eval(Container.DataItem, "title") %>' /> <br> <asp:textbox runat="server" Text='<%# DataBinder.Eval(Container.DataItem, "country") %>' /> <br> <asp:textbox runat="server" textmode="multiline" rows="9" Text='<%# DataBinder.Eval(Container.DataItem, "notes") %>' /> </edititemtemplate>

As Figure 4-11 shows, edit templates can transform a powerful (but sometimes anonymous) HTML table into an awesome repository of features and functionality. The full source code for the EditWithImages.aspx application is available on the companion CD.

Figure 4-11

Using all the features of templates gives you so much flexibility when working with in-place editing in DataGrid controls.



Building Web Solutions with ASP. NET and ADO. NET
Building Web Solutions with ASP.Net and ADO.NET
ISBN: 0735615780
EAN: 2147483647
Year: 2002
Pages: 75
Authors: Dino Esposito

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net