Personal notes on software development.
For Java technologies check my dedicated site

Pages

  • Add a hyperlink (that uses the querystring for args) to each row [1]:
Include a link titled "View Products" in each GridView row that, when clicked, takes the user to ProductsForSupplierDetails.aspx passing in the selected row's SupplierID value through the querystring.

For example, if user clicks on the View Products link for the Tokyo Traders supplier (which has a SupplierID value of 4), they should be sent to ProductsForSupplierDetails.aspx?SupplierID=4.

To accomplish this, add a HyperLinkField to the GridView, which adds a hyperlink to each GridView row. Start by clicking the Edit Columns link from the GridView's smart tag. Next, select the HyperLinkField from the list in the upper left and click Add to include the HyperLinkField in the GridView's field list.
 The HyperLinkField can be configured to use the same text or URL values the link in each GridView row, or can base these values on the data values bound to each particular row. To specify a static value across all rows use the HyperLinkField's Text or NavigateUrl properties. Since we want the link text to be the same for all rows, set the HyperLinkField's Text property to View Products.
 To set the text or URL values to be based on the underlying data bound to the GridView row, specify the data fields the text or URL values should be pulled from in the DataTextField or DataNavigateUrlFields properties. DataTextField can only be set to a single data field; DataNavigateUrlFields, however, can be set to a comma-delimited list of data fields.

We frequently need to base the text or URL on a combination of the current row's data field value and some static markup. In this tutorial, for example, we want the URL of the HyperLinkField's links to be ProductsForSupplierDetails.aspx?SupplierID=supplierID, where supplierID is each GridView's row's SupplierID value.

Notice that we need both static and data-driven values here: the ProductsForSupplierDetails.aspx?SupplierID= portion of the link's URL is static, whereas the supplierID portion is data-driven as its value is each row's own SupplierID value.

To indicate a combination of static and data-driven values, use the DataTextFormatString and DataNavigateUrlFormatString properties. In these properties enter the static markup as needed and then use the marker {0} where you want the value of the field specified in the DataTextField or DataNavigateUrlFields properties to appear. If the DataNavigateUrlFields property has multiple fields specified use {0} where you want the first field value inserted, {1} for the second field value, and so on.

Applying this to our tutorial, we need to set the DataNavigateUrlFields property to SupplierID, since that's the data field whose value we need to customize on a per-row basis, and the DataNavigateUrlFormatString property to ProductsForSupplierDetails.aspx?SupplierID={0}.

  •  The EmptyDataText property [1]:
If the user clicks on the View Products link for a supplier that doesn't have any products, the ProductsBySupplierDataSource ObjectDataSource in ProductsForSupplierDetails.aspx won't return any results. The GridView bound to the ObjectDataSource won't render any markup resulting in a blank region on the page in the user's browser. To more clearly communicate to the user that there are no products associated with the selected supplier we can set the GridView's EmptyDataText property to the message we want displayed when such a situation arises. I've set this property to "There are no products provided by this supplier":

<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" 
   DataKeyNames="ProductID" DataSourceID="ObjectDataSource1"
   EmptyDataText ="Não existem produtos deste fornecedor."> 

  • Creating a Selectable GridView [2]
Simply check the Enable Selection checkbox in the GridView's smart tag, which will add a Select button to each row.

This adds a CommandField to the ProductsGrid GridView with its ShowSelectButton property set to True. This results in a Select button for each row of the GridView. By default, the Select buttons are rendered as LinkButtons, but you can use Buttons or ImageButtons instead through the CommandField's ButtonType property.

<asp:GridView ID="ProductsGrid" runat="server" AutoGenerateColumns="False" 
    DataKeyNames="ProductID" DataSourceID="ObjectDataSource1">
    <Columns>
        <asp:CommandField ShowSelectButton="True"
                 ButtonType="Link" SelectText="Selecionar" />
        <asp:BoundField DataField="ProductName" HeaderText="ProductName" 
            SortExpression="ProductName" />
        <asp:BoundField DataField="UnitPrice" HeaderText="UnitPrice" 
            SortExpression="UnitPrice" />
    </Columns>    
</asp:GridView>

When a GridView row's Select button is clicked a postback ensues and the GridView's SelectedRow property is updated. In addition to the SelectedRow property, the GridView provides the:
 The DataKeyNames property is used to associate one or more data field values with each row and is commonly used to attribute uniquely identifying information from the underlying data with each GridView row: 
  • SelectedValue property: returns the value of the first DataKeyNames data field for the selected row;
  • SelectedDataKey property returns the selected row's DataKey object, which contains all of the values for the specified data key fields for that row.
The DataKeyNames property is automatically set to the uniquely-identifying data field(s) when you bind a data source to a GridView, DetailsView, or FormView through the Designer. While this property has been set for us automatically, for the selectable GridView to work properly the DataKeyNames property must be set properly. (In this example we must ensure that the DataKeyNames property is set to "ProductID").

  • Disabling the Edit Button in each row based on the row data [3]:
The picture below shows a GridView where each "Discontinued" product has its "Edit" button disabled:
This can be achieved with the following code logic in the GridViews RowDataBound event (note: for this example the CommandField for the Edit Button was converted to a TemplateField where a Edit LinkButton has the id "EditButton". This way we can use the e.Row.FindControl("EditButton") to get a reference to it):

protected void ProductsBySupplier_RowDataBound(object sender, GridViewRowEventArgs e)
{ 
    if (e.Row.RowType == DataControlRowType.DataRow)
    {
        //Get a reference to the product row
        Northwind.ProductsRow product = (Northwind.ProductsRow
                               ((System.Data.DataRowView)e.Row.DataItem).Row;

        //if the product is discontinued disable the edit button
        if (product.Discontinued)
        {               
            LinkButton editButton = (LinkButton)e.Row.FindControl("EditButton");
            editButton.Visible = false;
        }
    }        
} 

If we want to use the CommandField instead of converting it into a TemplateField then the reference to the Edit button can be achieved with:
 LinkButton editButton = (LinkButton)e.Row.Cells[0].Controls[0];

GridView Paging notes:

"Default Paging" Vs "Custom Paging" [5]:

  • Default Paging can be implemented by simply checking the Enable Paging option in the data Web control s smart tag; however, whenever viewing a page of data, the ObjectDataSource retrieves all of the records, even though only a subset of them are displayed in the page
  • Custom Paging improves the performance of default paging by retrieving only those records from the database that need to be displayed for the particular page of data requested by the user; however, custom paging involves a bit more effort to implement than default paging

Paging properties and methods [4]:

AllowPaging: Gets or sets a value indicating whether the paging feature is enabled;
PageSize: Gets or sets the number of records to display on a page in a GridView control;
PageIndex: indicates the current page being viewed (is indexed starting at 0, in the first page of data it will equal 0);
PageCount: indicates the total number of pages (starts counting at 1);
PagerStyle: indicates the style information for the paging interface (can specify settings like BackColor, ForeColor, CssClass, HorizontalAlign, and so on);
PagerSettings: contains a bevy of properties that can customize the functionality of the paging interface. Some examples are:
  • PagerSettings-PageButtonCount: indicates the maximum number of numeric page numbers displayed in the paging interface (the default is 10);
  • PagerSettings-Mode: indicates how the paging interface operates (can be set to:NextPrevious; NextPreviousFirstLast; Numeric; NumericFirstLast);

Custom Paging properties and methods [5]:

ASP.NET has already a built in mechanism to implement custom paging. To use it we must configure a set of properties of the web control (ex. GridView) associated DataSource:
  • SelectMethod: the BLL method to invoke to obtain the table data (ex. SelectMethod="GetProductsPaged"). This property is set when using the DataSource Configuration Wizard.
    Example of the Get
  • EnablePaging: must be set to true, indicating to the ObjectDataSource that it must pass to the SelectMethod two additional parameters, one to specify the Start Row Index (StartRowIndexParameterName), and one to specify the Maximum Rows (MaximumRowsParameterName);
  • StartRowIndexParameterName: the name of the first input parameter passed into the SelectMethod for custom paging purposes (ex. StartRowIndexParameterName="startRowIndex");
  • MaximumRowsParameterName: the name of the second input parameter passed into the SelectMethod for custom paging purposes (ex. MaximumRowsParameterName="maximumRows");
  • SelectCountMethod: the BLL method to invoke that returns the total number of records being paged through (ex. SelectCountMethod="TotalNumberOfProducts"); 
  • SortExpression: optional, in case we want to use sort with the custom paging. This property informs the ObjectDataSource to pass in the SortExpression parameter to the BLL method, based on the column that the user has requested to sort the results by. This property should be set to the same name of the parameter on the BLL method [6];
Note: if you used the DataSource Configuration Wizard it automaticly added  two <asp:Parameter> elements for the GetProductsPaged method s input parameters. By setting EnablePaging to true, these parameters will be passed automatically. So, remove the startRowIndex and maximumRows <asp:Parameter> Elements from the ObjectDataSource s Declarative Markup.


Paging Events [4]:

When a user sorts or pages through data, a workflow unfolds:
  1. A postback ensues
  2. The data Web control s pre-level event fires (PageIndexChanging or Sorting)
  3. All of the data is re-retrieved by the ObjectDataSource
  4. The data Web control s post-level event fires (PageIndexChanged or Sorted)

GridView Sorting Notes

Unable sort link on some GridViews Headers[4]:

When sorting is enabled on a GridView, each GridView field automatically has its SortExpression property assigned to the name of the data field in the ProductsRow class. For example, the ProductName BoundField's SortExpression is set to "ProductName", as shown in the following declarative markup:
<asp:BoundField DataField="ProductName" HeaderText="Product" 
     SortExpression="ProductName" />
A field can be configured so that it s not sortable by clearing out its SortExpression property (assigning it to an empty string):
<asp:BoundField DataField="ProductName" HeaderText="Product
     SortExpression="" />

Examining the Sorting Event Workflow [4]:

The following list details the sequence of steps that transpires when an end user sorts the data in a GridView:
  1. The GridView s Sorting event fires
  2. The GridView s SortExpression property is set to the SortExpression of the field whose sorting header LinkButton was clicked
  3. The ObjectDataSource re-retrieves all of the data from the BLL and then sorts the data using the GridView s SortExpression
  4. The GridView s PageIndex property is reset to 0, meaning that when sorting the user is returned to the first page of data (assuming paging support has been implemented)
  5. The GridView s Sorted event fires
Like with default paging, the default sorting option re-retrieves all of the records from the BLL. When using sorting without paging or when using sorting with default paging, there s no way to circumvent this performance hit (short of caching the database data). However,  it s possible to efficiently sort data when using custom paging.


GridView Render Control hierarchy [7]:

The process of data binding builds up the GridView s control hierarchy, which in reality is simply a Table instance composed of a collection of rows, each of which is composed of a collection of cells.

Specifically, the GridView s control collection contains:
  • a Table object at its root;
  • this Table contains multiple GridViewRow (which is derived from the TableRow class) for each record in the DataSource bound to the GridView;
  • and a TableCell object in each GridViewRow instance for each data field in the DataSource.
This table can be obtained with:
// Reference the Table the GridView has been rendered into 
Table table = (Table)SomeGridView.Controls[0];



Other Notes:
As discussed in this [article] it is vitally important that the GridView s view state be enabled (the default behavior) whenInserting, Updating or Deleting Data. If you set the GridView s EnableViewState property to false, you run the risk of having concurrent users unintentionally deleting or editing records. See WARNING: Concurrency Issue with ASP.NET 2.0 GridViews/DetailsView/FormViews that Support Editing and/or Deleting and Whose View State is Disabled for more information.

Related articles:
[1] - Master/Detail Filtering Across Two Pages
[2] - Master/Detail Using a Selectable Master GridView with a Details DetailView
[3] - Limiting Data Modification Functionality Based on the User
[4] - Paging and Sorting Report Data (see Step 5) 
[5] - Efficiently Paging Through Large Amounts of Data
[6] - Sorting Custom Paged Data
[7] - Creating a Customized Sorting User Interface

No comments:

Post a Comment