[referrence]GridView, DetailsView, and SqlDataSource Interaction

from:
http://www.dotnetjohn.com/articles.aspx?articleid=236
http://www.dotnetjohn.com/articles.aspx?articleid=241

GridView, DetailsView, and SqlDataSource Interaction Part 1


The GridView, DetailsView, and SqlDataSource controls are good at setting up a data-driven web site. However, there are times when you need to take other factors into consideration, to improve the user experience. Part 1 of this series will look at some of the basic things that can be done.
By: Brian Mains Spacer Date: May 9, 2007 Spacer Printer Friendly Version

Introduction

This article will show you how you can use the GridView, DetailsView, and SQLDataSource controls together to create a comprehensive web site. This will be a multipart article talking about the various facets of using these three articles together. The article will make use of the AdventureWorks database, so if you do not have that installed, you can download it freely from Microsoft's web site. In addition, this article assumes you have an understanding of the GridView, DetailsView, and SqlDataSource controls, and how they can interrelate on a basic scale. It is also helpful to understand the various parameters of the data source controls, and how they can automatically map to server controls, query string values, and other sources.

Data Source Initial Binding

Sometimes you want to late-bind a GridView, for several reasons. Binding a GridView immediately means that it will hit against the database, even if no valid criteria have been passed to the parameter. There are several ways to stop this. The first is to not assign the DataSourceID property initially; this will prevent the gridview control from binding immediately, and show the EmptyDataText or EmptyDataTemplate message.

Another way to prevent loading the data if no results are present is to catch the data source's Selecting event handler, and cancel the query as such:

    void sdsSearch_Selecting ( object sender, ObjectDataSourceSelectEventArgs e )

    {

        e.Cancel = string.IsNullOrEmpty ( this.txtSearchText.Text );

    }

This works well in preventing the query, but does not prevent the empty data message from appearing in the GridView. Late-binding handles that.

Handling Multiple Data Sources

There is another reason to late-bind the DataSourceID property. There may be multiple sources; for instance, the application can have multiple data source controls. Take for instance, a product search. You may search a product by letter, by name, or by a category, for example. Each of these means can be its own data source. When the user chooses the appropriate search mechanism, the code-behind page attaches that data source control to the grid and a binding occurs, such as below:

    void lnkLetterSelection_Click ( object sender, EventArgs e )

    {

        this.gvwResults.DataSourceID = this.sdsLetter.ID;

        this.gvwResults.DataBind ( );

    }

 

    void lnkTextSearch_Click ( object sender, EventArgs e )

    {

        this.gvwResults.DataSourceID = this.sdsSearch.ID;

        this.gvwResults.DataBind ( );

    }

 

    void lnkCategorySelection_Click ( object sender, EventArgs e )

    {

        this.gvwResults.DataSourceID = this.sdsCategory.ID;

        this.gvwResults.DataBind ( );

    }

In this manner, the gridview is late-bound with the correct data store. In this case, enabling viewstate for the grid is essential.

Paging

When using paging, the GridView/SQLDataSource controls can handle this automatically, meaning you do not have to write a single line of code to sort the data by a specific column or page through index values. However, say the gridview is bound to a form that contains search criteria. Furthermore, a data source control is linked to the parameters in the field, When the search button is clicked, all that is needed is for the grid to rebind because the parameters map to the search form fields. Before you rebind, you should consider resetting the page index to zero for several reasons.

Because the criteria changes, most users like to start over from the beginning; it's a natural behavior because usually the most relevant results are at the beginning, and oftentimes people don't like to feel they've missed something by glossing over a page or two of search results. In addition, the new data results may contain less total pages than the previous one, which could throw an exception.

So when binding, I use a private method, which always reset the paging value to zero as such:

    private void BindGrid ( )

    {

        this.gvwResults.PageIndex = 0;

        this.gvwResults.DataBind ( );

    }


Adding Rows Using the Details View

The DetailsView is a mechanism that can add, delete, or update items in a data source. Oftentimes, applications use a master/details view approach, where the master is the gridview with all the pertinent results, and the details view shows a single item's details, along with providing the ability to insert, update, or delete. These two controls work well together, but there are times when you need to control this interaction programmatically. For instance, the detailsview is usually bound to a gridview selection, which means there have to be items in the data source for the grid view to show data and for the details view to render. However, what if you have no data, and you need to get started inserting items? This information isn't shown immediately.

This is where it is helpful to have a link somewhere on the page, that can trigger the details view to change it's display mode. By default, details view is in read mode. This property can be changed through the ChangeMode method at run time, or through the DefaultMode property at design time. The link button's click event handler can programmatically change the current display mode, so when no records are available, the insert functionality can still be invoked. Even when there is data, to insert an item one must select an entry in the gridview, which isn't the most user-friendly.

    void lnkAddProduct_Click ( object sender, EventArgs e )

    {

        this.dvwProduct.ChangeMode ( DetailsViewMode.Insert );

        this.dvwProduct.DataBind ( );

    }

There are other options as well. Using the AlwaysVisibleControlExtender from the ASP.NET AJAX Control Toolkit (http://ajax.asp.net/ajaxtoolkit/AlwaysVisibleControl/AlwaysVisibleControl.aspx), you can put your administrative links that invoke creating a new row in the details view, or any other option, in a panel that is extended by the control extender. Then, the panel always appears visible, follows you throughout the page, and could be programmatically shown/hidden.

In the next article, I plan to show some of the error-handling aspects of the controls, as well as bring in ASP.NET AJAX into the mix.


GridView, DetailsView, and SqlDataSource Interaction Part 2


This article will show you how you can use the GridView, DetailsView, and SQLDataSource controls together to create features in a web site. This will be a multipart article talking about the various facets of using these three articles together.
By: Brian Mains Spacer Date: August22, 2007 Spacer Download Spacer Download the code Spacer printer Printer Friendly Version

Introduction

This article will show you how you can use the GridView, DetailsView, and SQLDataSource controls together to create features in a web site. This will be a multipart article talking about the various facets of using these three articles together. The article will make use of the AdventureWorks database, so if you do not have that installed, you can download it freely from Microsoft's web site. In addition, this article assumes you have an understanding of the GridView, DetailsView, and SqlDataSource controls, and how they can interrelate on a basic scale. It is also helpful to understand the various parameters of the data source controls, and how they can automatically map to server controls, query string values, and other sources.

A gridview, when linked to a details view, can be shown in a modal form; what I mean by that is, it can be shown in a popup window, where the main form is grayed out and only this window appears. The easiest way to implement this is using the AJAX Control Toolkit. To set this up, create a gridview bound to a source. Upon selecting an item, the selected index changed event fires, the details view data source control linked to the SelectedValue property populates the details view, and the details view will show the item in the popup.

Linking a details view item to a selection in the grid view is well documented on the web and won’t be discussed here. The process to do the popup is a little more complex. To understand how it works, realize that a modal popup extender is linked to an object to popup (a panel in this case) and a target that invokes the popup (a button in this case). It is possible to show and hide the popup programmatically (on the server) through the Show and Hide methods. Either way it is invoked, the extender still requires a button to trigger the event. To get around this, I usually use a hidden button, and invoke the panel through the Show method.

To make all of this work asynchronously, it requires that the grid/details view be wrapped in an update panel. The content of the update panel is shown below:


<asp:GridView id="gvwProducts" runat="server" DataSourceID="sdsProducts" AllowPaging="True" AllowSorting="True" AutoGenerateSelectButton="True" DataKeyNames="ProductID" PageSize="25">
</asp:GridView>
<asp:SqlDataSource id="sdsProducts" runat="server" ConnectionString="<%$ ConnectionStrings:AW %>" SelectCommand="SELECT [ProductID], [Name], [ProductNumber], [StandardCost], [Size], [ListPrice] FROM Production.[Product] ORDER BY [Name]" />

<asp:Panel id="pnlProduct" runat="server" CssClass="ModalPopupPanel" ScrollBars="Horizontal">
  <asp:LinkButton id="lnkCloseProduct" runat="server">Close</asp:LinkButton>
  <br />

  <asp:DetailsView id="dvwProduct" runat="server" DataKeyNames="ProductID”>
  </asp:DetailsView>
  <asp:SqlDataSource id="sdsProduct" runat="server" ConnectionString="<%$ ConnectionStrings:AW %>" SelectCommand="SELECT * FROM Production.[Product] WHERE ([ProductID] = @ProductID)" >
    <SelectParameters>
      <asp:ControlParameter ControlID="gvwProducts" Name="ProductID" PropertyName="SelectedValue"
        Type="Int32" />
    </SelectParameters>
  </asp:SqlDataSource>
</asp:Panel>
<ajax:ModalPopupExtender id="extProduct" runat="server" TargetControlID="btnTrigger"
  PopupControlID="pnlProduct" CancelControlID="lnkCloseProduct" BackgroundCssClass="ModalPopupBackground" />
<asp:Button id="btnTrigger" runat="server" style="display:none" />

To invoke the popup, tap into the selected index changed event as such:

Protected Sub gvwProducts_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles gvwProducts.SelectedIndexChanged
  Me.extProduct.Show()
End Sub

The modal popup will show on screen, showing the details of the product. Clicking the close link works seamlessly because the modal popup links to an OK and a Cancel button, which the close button works like a cancel in this scenario. There is one drawback to this approach; it may not work correctly upon refreshing, which will popup the modal screen again. I've experienced that in one of my projects recently.

In addition, what about making a more detailed message in cases where you want to search for something and no results are found? There are many ways to handle this, but there are a few important notes you should know about first. If you have a gridview bound to a data source initially, and the data source is connected to a control (like a search text box), you may experience where the gridview binds to the data source without there being any text present and no rows are returned. This occurs by design, and there are ways to circumvent this premature query. One way is to tap into the Selecting event of the data source control. If no text has been entered into the search text box, the searched can be cancelled through e.Cancel = true. This stops the data query from taking place.

Protected Sub sdsResults_Selecting(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.SqlDataSourceSelectingEventArgs) Handles sdsResults.Selecting
  e.Cancel = String.IsNullOrEmpty(Me.txtSearchText.Text)
End Sub

The reason this is important is that if you have an EmptyDataTemplate defined or EmptyDataText set, this will display when no rows are returned. For a search page, the page initially loads and no search text can be entered, so an empty text message like "no records found" will be displayed erroneously. The scenario above can prevent that; there is another approach you can use, which is to not set the DataSourceID in the HTML markup. Instead, you assign it in code-behind whenever you have relevant search results, with code such as below:

If (string.IsNullOrEmpty(txtSearch.Text)) Then
  DisplayMessage("Please enter some search criteria")
Else
  gvwResults.DataSourceID = sdsResults.ID
  gvwResults.DataBind()
End If

This way, the grid is not directly linked, and only searched at the proper time. However, what if you wanted to create a more personalized "not found" message? To do that, you can leverage the approach above, and use the EmptyDataText property. Before binding, set that property as shown below:

Me.gvwResults.EmptyDataText = String.Format("Your search for '{0}' yielded no results", Me.txtSearchText.Text)

You would do this assignment before binding regardless, because that message shows itself appropriately. What about changing the display values of the data being displayed? For instance, maybe you want to change a boolean value from 1/0 or true/false to Yes/No, something a little more appropriate. In this case, you can override the RowCreated or RowDataBound event to change the value. If you want to change the value after the initial binding only, use RowDataBound, but use RowCreated to process the row data everytime. In this event, you can do something like the following, to format currency values to something more appropriate:

Protected Sub gvwResults_RowDataBound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewRowEventArgs) Handles gvwResults.RowDataBound
  e.Row.Cells(3).Text = Me.FormatCurrency(e.Row.Cells(3).Text)
  e.Row.Cells(5).Text = Me.FormatCurrency(e.Row.Cells(5).Text)
End Sub

This will convert the data appropriately. Being that you have access to the Row or to the Cell, you can change colors, fonts, styling, append javascript, or append CSS styles as appropriate. In the example above, if the value is below a certain amount, it could be colored appropriately. These are some of the things that can be done rather easily with the gridview and data source controls.

posted @ 2008-01-25 12:40  N/A2011  阅读(832)  评论(0编辑  收藏  举报