# Monday, June 22, 2009

CascadingDropDownLists, GridViews, and Dynamically selecting the appropriate ListItem during Edit...

okay, I apologize. I promised to do this weeks ago and am only finally getting it up. Hopefully it will be worth the wait...

If you are planning on simply using a DDL (and not Cascading), look here -> http://www.myfriedmind.com/techBlog/2009/06/04/DropDownListGridViewAndDynamicallySelectingTheAppropriateListItemDuringEdit.aspx

Note that this example uses a remote webservice (rather than a PageMethod) for the CascadingDropDownList calls and I have not included them to simplify the amount of code on this page, but they are fairly straightforward -> http://www.asp.net/AJAX/AjaxControlToolkit/Samples/CascadingDropDown/CascadingDropDown.aspx

Sample DataObject (in c#)

class MyObject
{
   public int ObjId { get; set; }
   public string StateAbbreviation { get; set; }
   public string ZipCode { get; set; }
}

Sample DataObject (in vb.net)

Class MyObject
   Public ObjId As Integer
   Public StateAbbreviation As String
   Public ZipCode As String
End Class

Entry on SampleGridView.aspx page (as simple as you can get it)

<asp:GridView runat="server" ID="lstMyData" DataKeyNames="ObjId"
    AutoGenerateColumns="false" EnableViewState="true"
    AutoGenerateEditButton="true"
    OnRowDataBound="lstMyData_RowDataBound" >
    <Columns>
        <asp:TemplateField>
            <ItemTemplate>
                <asp:Label runat="server" ID="lblState"    
                    Text='<%# Eval("StateAbbreviation") %>' />
            </ItemTemplate>
            <EditItemTemplate>
                <asp:DropDownList runat="server" ID="uxState" />
                <aKit:CascadingDropDown ID="ajxState" runat="server"
                    TargetControlID="uxState" Category="State" 
                    ServiceMethod="GetStates" />
            </EditItemTemplate>
        </asp:TemplateField>
        <asp:TemplateField>
            <ItemTemplate>
                <asp:Label runat="server" ID="lblZipCode"  
                   Text='<%# Eval("ZipCode") %>' />
            </ItemTemplate>
            <EditItemTemplate>
                <asp:DropDownList runat="server" ID="uxZipCode" />
                <aKit:CascadingDropDown ID="ajxZipCode" runat="server"
                    TargetControlID="uxZipCode" Category="ZipCode"
                    LoadingText="[Loading Zipcode...]"
                    ServicePath="WebServiceToReturnData.asmx" 
                    ServiceMethod="GetZipCode"
                  ParentControlID="uxState" />
            </EditItemTemplate>
        </asp:TemplateField>
    </Columns>
</asp:GridView>

Codebehind (in c#) SampleGridView.apx.cs (note this does NOT include the code to return the values)

protected void lstMyData_RowDataBound(object sender,
        GridViewRowEventArgs e)
{
    // verify this is a DataRow, not a Header, Footer, etc...
    if (e.Row.RowType == DataControlRowType.DataRow)
    {
        // in case you want to do something else here....
       
        // see if this is the Row used for Editing
        if ((e.Row.RowState & DataControlRowState.Edit) != 0)
        {
            // get the DataItem that is bound
            // and cast it accordingly
            MyObject _myObject = (MyObject)e.Row.DataItem;

            // get the CascadingDropDowns
            CascadingDropDown _ajxState =
                (CascadingDropDown) e.Row.FindControl("ajxState");
            CascadingDropDown _ajxZipCode =
                (CascadingDropDown) e.Row.FindControl("ajxZipCode");

            // the data is automatically updated via the Ajax,
            // so we merely need to select the item

            _ajxState.SelectedValue = _myObject.StateAbbreviation
            // _ajxState.ContextKey = this can be set here if you are using it;

            _ajxZipCode.SelectedValue = myObject.ZipCode;
        }
    }
}

Codebehind (in vb.net) SampleGridView.apx.cs (note this does NOT include the code to return the values)

Protected Sub lstMyData_RowDataBound(ByVal sender As Object, _
    ByVal e As System.Web.UI.WebControls.GridViewRowEventArgs) _
    Handles lstMyData.RowDataBound
    If e.Row.RowType = DataControlRowType.DataRow Then

            ' in case you want to do something else here....

            ' see if this is the Row used for Editing
            If (e.Row.RowState And DataControlRowState.Edit) <> 0 Then


                ' get the DataItem that is bound
                ' and cast it accordingly
                Dim _myObject As MyObject = _
                    DirectCast(e.Row.DataItem, MyObject)

                ' get the CascadingDropDowns
                Dim _ajxState As CascadingDropDown = _
                    DirectCast(e.Row.FindControl("ajxState"), CascadingDropDown)
                Dim _ajxZipcode As CascadingDropDown = _
                    DirectCast(e.Row.FindControl("ajxZipCode"), CascadingDropDown)

                ' ddl population should be handled by the Ajax
                ' ServiceMethod of the CascadingDropDown

                ' select the appropriate item
                _ajxState.SelectedValue = _myObject.StateAbbreviation
                _ajxZipCode.SelectedValue = _myObject.ZipCode

            End If
     End If
End Sub

Wednesday, July 01, 2009 8:09:59 AM (Central Daylight Time, UTC-05:00)
Another option with databound items is to use the SelectedValue property on a DropDownList. This property does not show up in Intellisense, but is allowed for run-time evaluated values. Here is sample code to display the list of Products in the Northwind database. When a product is selected for editing, a DropDownList of categories is populated with the proper value selected.

Note: In order to run this example, you will need to have a copy of the Northwind database and a connection string named NorthwindConnectionString defined in your web.config that points to it.

<%@ Page Language="VB" AutoEventWireup="false" CodeFile="Default.aspx.vb" Inherits="_Default" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>DropDownList SelectedValue Example</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:GridView ID="gvProducts" runat="server" AutoGenerateColumns="False" DataKeyNames="ProductID"
DataSourceID="sdsProducts">
<Columns>
<asp:CommandField ShowEditButton="True" />
<asp:BoundField DataField="ProductName" HeaderText="ProductName" SortExpression="ProductName" />
<asp:TemplateField HeaderText="CategoryName" SortExpression="CategoryName">
<EditItemTemplate>
<asp:DropDownList ID="ddlCategories" runat="server" DataSourceID="sdsCategories"
DataTextField="CategoryName" DataValueField="CategoryID" SelectedValue='<%#Bind("CategoryID") %>'>
</asp:DropDownList><asp:SqlDataSource ID="sdsCategories" runat="server" ConnectionString="<%$ ConnectionStrings:NorthwindConnectionString %>"
SelectCommand="SELECT [CategoryID], [CategoryName] FROM [Categories] ORDER BY [CategoryName]"></asp:SqlDataSource>
</EditItemTemplate>
<ItemTemplate>
<asp:Label ID="lblCategoryName" runat="server" Text='<%# Bind("CategoryName") %>'></asp:Label>
</ItemTemplate>
</asp:TemplateField>
<asp:BoundField DataField="UnitPrice" HeaderText="UnitPrice" SortExpression="UnitPrice" DataFormatString="{0:c}" />
<asp:BoundField DataField="UnitsInStock" HeaderText="UnitsInStock" SortExpression="UnitsInStock" />
</Columns>
</asp:GridView>
<asp:SqlDataSource ID="sdsProducts" runat="server" ConnectionString="<%$ ConnectionStrings:NorthwindConnectionString %>"
SelectCommand="SELECT [ProductName], [Products].[CategoryID], [CategoryName], [UnitPrice], [UnitsInStock], [ProductID] FROM [Products] JOIN [Categories] ON Products.CategoryID = Categories.CategoryID ORDER BY [ProductName]">
</asp:SqlDataSource>
</div>
</form>
</body>
</html>
Shawn
Wednesday, July 01, 2009 8:11:37 AM (Central Daylight Time, UTC-05:00)
Good point!
papabear
Comments are closed.