Pages

Advertisement

Sunday, August 5, 2007

ASP.NET Data Control Series - Part 2

The intent of this series is to provide more information concerning the functionality and limitations of the available ASP.NET 2.0 data controls. This will mostly be demonstrated through the use of code samples. Once this series is complete, I will demonstrate how one can AJAX enable some of these samples to improve the overall user experience. Therefore, this series will address the basics first before moving onto more advanced tools. Many will feel that there is enough information available concerning these matters. However, for completeness sake, I feel it is important to provide a good foundation from which to launch future articles from. The articles in this series will address typical scenarios that one might encounter in terms of developing with ASP.NET data controls.

There will be three parts in this series:

  • Part 1 – ASP.NET GridView
  • Part 2 – ASP.NET FormView and DetailsView
  • Part 3 – ASP.NET Repeater and DataList

The SqlDataSource control is used throughout the series for simplicities sake.

Part 2 - ASP.NET FormView Data Control

This is the second article in a three part series of articles pertaining to the understanding and application of ASP.NET 2.0 data controls. This article will address common functionality that may be required from ASP.NET FormView data controls.

Level: Novice - Intermediate

Prerequisites:

  • In order for the sample code to run, one will require the Pubs database running on either SqlExpress or Sql2005.
  • An understanding of C# and ASP.NET development code

Please download the code here

Introduction

Based on various Microsoft documentation, the ASP.NET FormView can be summarised as follows.

Displays the values of a single record from a data source using user-defined templates. The FormView control allows you to edit, delete, and insert records. It is similar to the DetailsView control, except it displays user-defined templates instead of row fields.

The FormView control supports the following features:

  • Binding to data source controls, such as SqlDataSource and ObjectDataSource.
  • Built-in inserting capabilities.
  • Built-in updating and deleting capabilities.
  • Built-in paging capabilities.
  • Programmatic access to the FormView object model to dynamically set properties, handle events, and so on.
  • Customizable appearance through user-defined templates, themes, and styles.
Example Details

For this example, a SqlDataSource is used to retrieve a list of authors from the database. A FormView will be used to display Author information. For each Author, a list of book titles is loaded into a GridView data control. The Titles GridView is nested within the FormView data control as a master/detail setup. The FormView behaving as the master and the Tiels GridView as the detail. Also, one is able to open a modal dialog displaying publisher information that an Author is related to. It is alos possible to add a new Title to an author from the Author FormView data control. Therefore, not only does the Author FormView have a GridView nested within it, but also another FormView data control. The whole point of this exercise is to highlight how easy it is to provide rich edit functionality using the FormView data control.

We will be using the SqlDataSource as a data provider in this example. The example will demonstrate the following features:

  • Bind FormView to a SqlDataSource (It should be noted that I only use the SqlDataSource for demonstration purposes. I favour the ObjectDataSource over the SqlDataSource in terms of the development I have been involved in)
  • Search data using a query statement, ASP.NET control parameters, and ASP.NET controls (TextBox and DropDownList) as the input
  • Edit and Update behaviour with the ASP.NET RequiredFieldValidator and CompareValidator controls.
  • Delete with confirmation dialog
  • Master/Details using a modal dialog
  • Master/Detail between FormView (master) and GridView (detail)
  • Using the DataBound event
  • Implement custom Paging

Note: Please refer to the solution code concerning the following scenarios.

Bind FormView to a SqlDataSource

For this example, a SqlDataSource is used as the FormView data source. The FormView DataSourceID is set to the id of the SqlDataSource. Because paging functionality will be demonstrated, AllowPaging is set to true. The DataKeyNames property is used as a primary key/s (value that uniquely identifies a record) and is set to the author id (au_id).

<asp:FormView ID="AuthorFormView"
 
runat="server" AllowPaging="True"
 
DataKeyNames="au_id" DataSourceID="AuthorSqlDataSource"
 
Width="800px" OnDataBound="AuthorFormView_DataBound"
 
OnModeChanged="AuthorFormView_ModeChanged">
 

The OnModeChanged event is used to determine what mode the Author FormView data control is in. In this case we use it to determine whether the Author FormView is in edit or insert mode. If it is, the Search Panel is disabled.


protected void AuthorFormView_ModeChanged(object sender, 
 
EventArgs e)
 
{
 
if (AuthorFormView.CurrentMode == FormViewMode.Edit
 
    || AuthorFormView.CurrentMode == FormViewMode.Insert)
 
  {
 
    SearchPanel.Enabled = false;
 
  }
 
else
 
  {
 
    SearchPanel.Enabled = true;
 
  }
 
}
 

The result from binding to the SqlDataSource is demonstrated as follows.


Search data

This example demonstrates how to search data within the context of a FormView control

The following code highlights the setup for the ASP.NET controls that are used as part of the search.

This is the ASP.NET code required for the setup of the Search Panel


<asp:Panel ID="SearchPanel" CssClass="Panel"
 
runat="server" Width="800px">
 
<fieldset class="Panel">
 
<legend><strong>Search</strong></legend>
 
<table width="800px" cellpadding="6px">
 
<tr>
 
<td>
 
             Author:&nbsp;<asp:TextBox ID="AuthorSearchTextBox"
 
runat="server" Width="200px" /></td>
 
<td>
 
             Publisher:&nbsp;<asp:DropDownList
 
ID="PublisherSearchDropDownList"
 
runat="server" Width="204px"
 
OnDataBound="PublisherSearchDropDownList_OnDataBound"
 
DataSourceID="PublisherSqlDataSource"
 
DataTextField="pub_name"
 
             DataValueField="pub_id" /></td>
 
</tr>
 
<tr>
 
<td colspan="2">
 
<asp:Button ID="AuthorSearchButton"
 
Text="Search" runat="server"
 
BackColor="LightSteelBlue" /></td>
 
</tr>
 
</table>
 
</fieldset>
 
</asp:Panel>
 

The result is as follows.


The Author FormView SqlDataSource is setup as follows to retrieve data based on search criteria. ASP Control Parameters are used as Select parameters


<SelectParameters>
 
<asp:ControlParameter ControlID="AuthorSearchTextBox"
 
Name="author" PropertyName="Text" DefaultValue=" " />
 
<asp:ControlParameter ControlID="PublisherSearchDropDownList"
 
DefaultValue=" " Name="publisher"
 
PropertyName="SelectedItem.Text" />
 
</SelectParameters>
 

The SQL Select command is setup as follows.

SelectCommand="SELECT DISTINCT A.* FROM [Authors] A LEFT JOIN [TitleAuthor] TA ON A.au_id = TA.au_id LEFT JOIN [Titles] T ON TA.title_id = T.title_id LEFT JOIN Publishers P ON T.pub_id = P.pub_id WHERE (A.au_lname like '%' + @author + '%' OR A.au_fname like '%' + @author + '%' OR @author = '') AND (P.pub_name LIKE '%' + @publisher + '%' OR @publisher = '') ORDER BY A.au_lname ASC"

One can search by Author AND/OR Publisher. The results are as follows.



Edit and Update behaviour with the ASP.NET RequiredFieldValidator and CompareValidator controls

For this scenario please refer to the solution code.

The point of this scenario is to illustrate how one might nest data controls in order to achieve rich edit functionality. In this scenario, a FormView (New Title) and a GridView (Title Detail) is nested within a FormView (Author Detail).

The following screen shot illustrates that when a record is in edit mode; all author detail is required and cannot be left empty. If an attempt is made to update the row, a client-side validation event is raised to indicate that the author fields are required. It should also be noted that the Title GridView now provides an edit option. Also, one is able to add a new Title from this point.

The code to setup the Command Buttons to put the FormView in Edit or New mode is demosntrated as follows. Take note of the CommandName property.


<tr>
 
<td colspan="5">
 
<asp:LinkButton ID="EditButton"
 
runat="server" CausesValidation="False"
 
CommandName="Edit" Text="Edit" />
 
<asp:LinkButton ID="DeleteButton"
 
runat="server" CausesValidation="False"
 
CommandName="Delete"
 
OnClientClick="return ConfirmDelete();"
 
Text="Delete" />
 
<asp:LinkButton ID="NewButton"
 
runat="server" CausesValidation="False"
 
CommandName="New" Text="New" />
 
</td>
 
</tr>
 

Edit an Author


Edit Title for Author


<tr>
 
<td colspan="5">
 
<asp:LinkButton ID="InsertTitleButton"
 
runat="server" CausesValidation="True"
 
CommandName="Insert" Text="Insert"
 
ValidationGroup="NewTitleValidationGroup">
 
</asp:LinkButton>
 
<asp:LinkButton ID="InsertCancelTitleButton"
 
runat="server" CausesValidation="False"
 
CommandName="Cancel" Text="Cancel">
 
</asp:LinkButton>
 
</td>
 
</tr>
 


Add new Title


Delete with confirmation dialog

Unfortunately, there is no setting that one can enable to allow one to have a confirmation dialog popup should a delete action be initiated. The following snippet demonstrates a way that one might use to create this kind of behaviour.

Add some javascript to prompt a user before removing an item.


/**
 
 * Raise a confirmation dialog to confirm the requested deletion
 
 * of a record
 
 **/
 
function ConfirmDelete()
 
{
 
return confirm("Are you sure you wish to remove the selected item?");      
 
}
 
An ‘OnClientClick’ event handler is configured for the Delete ImageButton. The event handler will execute the ‘ConfirmDelete()’ javascript function. 
 
<asp:LinkButton ID="DeleteButton"
 
runat="server" CausesValidation="False"
 
CommandName="Delete" OnClientClick="return ConfirmDelete();"
 
Text="Delete" />
 

The resultant behaviour is as follows.


Master/Details using a modal dialog

The following code snippet demonstrates how one might open a dialog window from a FormView control. When the ‘Show Publisher Detail’ link button is clicked, a modal dialog will be opened. Upon opening, the dialog window will load a FormView control with a summary of Publisher detail based on AuthorID. The AuthorID is passed as a parameter as part of the javascript code required to open a modal dialog as can be seen in the snippet below.


/**
 
 * Show a modal dialog that will load a page containing a GridView
 
 * that will be populated with OrderDetail records based on the 
 
 * provided 'PRoductID'
 
 */
 
function ShowPublisherDetail(AuthorID)
 
{
 
  window.showModalDialog("PublisherInfo.aspx?AuthorID=" + AuthorID, "", 
 
"dialogWidth:430px;dialogHeight:200px;resizable:no;scrollbars:no");
 
}
 
A static method (GetClientClick()) in the code behind is used as part of this functionality.
 
protected static string GetClientClick(object value)
 
{
 
return String.Format(
 
"ShowPublisherDetail('{0}'); return false;",
 
    value.ToString());
 
}
 
The 'Show Publisher Detail' Link Button is configured as follows.
 
<tr>
 
<td colspan="5">
 
<asp:LinkButton ID="ShowPublisherDetailLinkButton"
 
runat="server" Text="Show Publisher Detail"
 
OnClientClick='<%# GetClientClick(Eval("au_id")) %>' />
 
</td>
 
</tr>
 

The result is as follows.


Master/Detail between FormView (master) and GridView (detail)

For each Author record that is retrieved, a GridView will be loaded with titles that have been authored according to the author id. The Author FormView behaves as the Master providing the AuthorId.

Please refer to the solution code for this example.


Implement custom Paging

It is possible to provide rich paging functionality by editing the PagerTemplate of the FormView. The following code snippets illustrate how this is achieved. Please refer to the following code in the actual code solution.

The following code illustrates the ASP.NET settings required to implement a custom paging template. Please take note of the ‘CommandArgument’ and ‘CommandName’ attributes.


<PagerSettings Mode="NextPreviousFirstLast"
 
Position="TopAndBottom" />
 
<PagerTemplate>
 
<asp:Panel ID="PagerTemplatePanel"
 
runat="server" CssClass="ItemTemplatePanel"
 
BackColor="lightsteelblue" Width="800px">
 
<table width="800px">
 
<tr valign="middle">
 
<td style="text-align: right; width: 340px">
 
<asp:ImageButton ID="FirstPageImageButton"
 
runat="server" AlternateText="First Page"
 
CommandName="Page" CommandArgument="First"
 
ImageUrl="~/Images/Bullets/left.gif" />
 
<asp:ImageButton ID="PreviousPageImageButton"
 
runat="server" AlternateText="Previous Page"
 
CommandName="Page" CommandArgument="Prev"
 
ImageUrl="~/Images/Bullets/left2.gif" />
 
</td>
 
<td style="text-align: center;
 
          width: 120px">
 
          Page&nbsp;<asp:DropDownList ID ="PageNumberDropDownList"
 
AutoPostBack="true"
 
OnSelectedIndexChanged="PageNumberDropDownList_OnSelectedIndexChanged"
 
runat="server" />&nbsp;of&nbsp;<asp:Label
 
ID="PageCountLabel" runat="server" />
 
</td>
 
<td style="text-align: left; width: 340px">
 
<asp:ImageButton ID="NextPageImageButton"
 
runat="server" AlternateText="Next Page"
 
CommandName="Page" CommandArgument="Next"
 
ImageUrl="~/Images/Bullets/right2.gif" />
 
<asp:ImageButton ID="LastPageImageButton"
 
runat="server" AlternateText="Last Page"
 
CommandName="Page" CommandArgument="Last"
 
ImageUrl="~/Images/Bullets/right.gif" />
 
</td>
 
</tr>
 
</table>
 
</asp:Panel>
 
</PagerTemplate>
 
The following code illustrates the initlaisation code required to enable the required custom paging functionality. 
 
/// <summary>
 
/// Initialise Pager Row Settings
 
/// </summary>
 
private void InitialiseFormViewPagerRow(FormViewRow formViewRow)
 
{
 
if (formViewRow != null)
 
  {
 
// Check the page index so that we can :
 
//  1. Disable the 'First' and 'Previous' paging image buttons if paging index is at 0
 
//  2. Disable the 'Last' and 'Next' paging image buttons if paging index is at the end
 
//  3. Enable all image buttons if the conditions of 1 and 2 are not satisfied
 
if (AuthorFormView.PageIndex == 0)
 
    {
 
// Disable 'First' and 'Previous' Paging image buttons
 
ImageButton firstPageImageButton = formViewRow.FindControl(
 
"FirstPageImageButton") as ImageButton;
 
ImageButton previousPageImageButton = formViewRow.FindControl(
 
"PreviousPageImageButton") as ImageButton;
 
if (firstPageImageButton != null && previousPageImageButton != null)
 
      {
 
        firstPageImageButton.Enabled = false;
 
        previousPageImageButton.Enabled = false;
 
      }
 
    }
 
else if ((AuthorFormView.PageIndex + 1) == AuthorFormView.PageCount)
 
    {
 
// Disable 'Last' and 'Next' Paging image buttons
 
ImageButton lastPageImageButton = formViewRow.FindControl(
 
"LastPageImageButton") as ImageButton;
 
ImageButton nextPageImageButton = formViewRow.FindControl(
 
"NextPageImageButton") as ImageButton;
 
if (lastPageImageButton != null && nextPageImageButton != null)
 
      {
 
        lastPageImageButton.Enabled = false;
 
        nextPageImageButton.Enabled = false;
 
      }
 
    }
 
else
 
    {
 
// Enable the Paging image buttons
 
ImageButton firstPageImageButton = formViewRow.FindControl(
 
"FirstPageImageButton") as ImageButton;
 
ImageButton previousPageImageButton = formViewRow.FindControl(
 
"PreviousPageImageButton") as ImageButton;
 
ImageButton lastPageImageButton = formViewRow.FindControl(
 
"LastPageImageButton") as ImageButton;
 
ImageButton nextPageImageButton = formViewRow.FindControl(
 
"NextPageImageButton") as ImageButton;
 
if (firstPageImageButton != null && lastPageImageButton != null &&
 
        previousPageImageButton != null && nextPageImageButton != null)
 
      {
 
        firstPageImageButton.Enabled = true;
 
        lastPageImageButton.Enabled = true;
 
        nextPageImageButton.Enabled = true;
 
        previousPageImageButton.Enabled = true;
 
      }
 
    }
 
// Get the DropDownList found as part of the Pager Row. 
 
// One can then initialise the DropDownList to contain
 
// the appropriate page settings. Eg. Page Number and 
 
// number of Pages
 
DropDownList pageNumberDropDownList = formViewRow.FindControl(
 
"PageNumberDropDownList") as DropDownList;
 
Label pageCountLabel = formViewRow.FindControl(
 
"PageCountLabel") as Label;
 
if (pageNumberDropDownList != null && pageCountLabel != null)
 
    {
 
for (int i = 0; i < AuthorFormView.PageCount; i++)
 
      {
 
int page = i + 1;
 
        pageNumberDropDownList.Items.Add(new ListItem(
 
          page.ToString(), i.ToString()));
 
      }
 
      pageNumberDropDownList.SelectedIndex = AuthorFormView.PageIndex;
 
      pageCountLabel.Text = AuthorFormView.PageCount.ToString();
 
    }
 
  }
 
}
 
/// <summary>
 
/// Handle the SelectedIndexChanged event for the Page Number
 
/// DropDownList. This allows one to select a page index via a
 
/// DropDownList.
 
/// </summary>
 
protected void PageNumberDropDownList_OnSelectedIndexChanged(
 
object sender, EventArgs e)
 
{
 
DropDownList pageNumberDropDownList = sender as DropDownList;
 
if (pageNumberDropDownList != null)
 
  {
 
if (AuthorFormView.DataItemCount > 0)
 
    {
 
if (pageNumberDropDownList.SelectedIndex < AuthorFormView.PageCount ||
 
        pageNumberDropDownList.SelectedIndex >= 0)
 
      {
 
        AuthorFormView.PageIndex = pageNumberDropDownList.SelectedIndex;
 
      }
 
    }
 
  }
 
}
 

The result of the aforementioned code is illustrated in the image below.


That’s it for Part 2 of ASP.NET data controls. Part 3 will address the ASP.NET DetailView and Repeater data controls.

1 comment:

  1. Their seo services are top notch. We have been using them for about 5 years now but they just showed us their new viral marketing packages that are state of the art mass marketing techniques becuase it's not just about seo
    anymore.
    Website Promotion from Atomic Seo was definitly a wise investment so yeah I would recommend their services.

    ReplyDelete