[C#][ASP.NET]在GridView中將DropDownList關聯另一個DropDownList歷險記

摘要:[C#][ASP.NET]在GridView中將DropDownList關聯另一個DropDownList歷險記

執行畫面如下:

.aspx如下


<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" 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></title>
</head>
<body>
    <form id="form1" runat="server">
    <asp:ScriptManager ID="ScriptManager1" runat="server">
    </asp:ScriptManager>
    time:<%=DateTime.Now.ToLongTimeString() %>
    <asp:GridView ID="GridView1" runat="server" AllowPaging="True" AllowSorting="True"
        AutoGenerateColumns="False" DataKeyNames="OrderID,ProductID" 
        DataSourceID="SqlDataSource1" PageSize="5" onrowupdated="GridView1_RowUpdated">
        <Columns>
            <asp:CommandField ShowDeleteButton="True" ShowEditButton="True" ShowSelectButton="True" />
            <asp:BoundField DataField="OrderID" HeaderText="OrderID" ReadOnly="True" SortExpression="OrderID" />
            <asp:TemplateField HeaderText="CategoryName" SortExpression="CategoryName">
                <EditItemTemplate>
                    <asp:UpdatePanel ID="UpdatePanel1" runat="server">
                        <ContentTemplate>
                            <asp:DropDownList ID="DropDownList1" runat="server" DataSourceID="SqlDataSource1"
                                DataTextField="CategoryName" DataValueField="CategoryID" AutoPostBack="True"
                                SelectedValue='<%# Eval("CategoryID") %>'>
                            </asp:DropDownList>
                        </ContentTemplate>
                    </asp:UpdatePanel>
                    <asp:SqlDataSource ID="SqlDataSource1" runat="server" ConnectionString="<%$ ConnectionStrings:NorthwindConnectionString %>"
                        SelectCommand="SELECT [CategoryID], [CategoryName] FROM [Categories]"></asp:SqlDataSource>
                </EditItemTemplate>
                <ItemTemplate>
                    <asp:Label ID="Label1" runat="server" Text='<%# Eval("CategoryName") %>'></asp:Label>
                </ItemTemplate>
            </asp:TemplateField>
            <asp:TemplateField HeaderText="ProductName" SortExpression="ProductName">
                <EditItemTemplate>
                    <asp:UpdatePanel ID="UpdatePanel2" runat="server">
                        <ContentTemplate>
                            <asp:DropDownList ID="DropDownList2" runat="server" DataSourceID="SqlDataSource2"
                                DataTextField="ProductName" DataValueField="ProductID" SelectedValue='<%# Bind_ProductID(DropDownList2) %>'>
                            </asp:DropDownList>
                        </ContentTemplate>
                    </asp:UpdatePanel>
                    <asp:SqlDataSource ID="SqlDataSource2" runat="server" ConnectionString="<%$ ConnectionStrings:NorthwindConnectionString %>"
                        SelectCommand="select ProductID,ProductName from Products WHERE ([CategoryID] = @CategoryID)  union select -1 as ProductID,'' as ProductName from Products order by ProductName">
                        <SelectParameters>
                            <asp:ControlParameter ControlID="DropDownList1" Name="CategoryID" PropertyName="SelectedValue"
                                Type="Int32" />
                        </SelectParameters>
                    </asp:SqlDataSource>
                </EditItemTemplate>
                <ItemTemplate>
                    <asp:Label ID="Label1" runat="server" Text='<%# Eval("ProductName") %>'></asp:Label>
                </ItemTemplate>
            </asp:TemplateField>
            <asp:BoundField DataField="UnitPrice" HeaderText="UnitPrice" SortExpression="UnitPrice" />
            <asp:BoundField DataField="Quantity" HeaderText="Quantity" SortExpression="Quantity" />
            <asp:BoundField DataField="Discount" HeaderText="Discount" SortExpression="Discount" />
        </Columns>
    </asp:GridView>
    <asp:SqlDataSource ID="SqlDataSource1" runat="server" ConnectionString="<%$ ConnectionStrings:NorthwindConnectionString %>"
        DeleteCommand="DELETE FROM [Order Details] WHERE [OrderID] = @OrderID AND [ProductID] = @ProductID"
        InsertCommand="INSERT INTO [Order Details] ([OrderID], [ProductID], [UnitPrice], [Quantity], [Discount]) VALUES (@OrderID, @ProductID, @UnitPrice, @Quantity, @Discount)"
        SelectCommand="SELECT [Order Details].OrderID, Categories.CategoryID, Categories.CategoryName, [Order Details].ProductID, Products.ProductName, 
 [Order Details].UnitPrice, [Order Details].Quantity, [Order Details].Discount 
 FROM [Order Details] INNER JOIN 
 Products ON [Order Details].ProductID = Products.ProductID INNER JOIN 
 Categories ON Products.CategoryID = Categories.CategoryID" UpdateCommand="UPDATE [Order Details] SET [UnitPrice] = @UnitPrice, [Quantity] = @Quantity, [Discount] = @Discount, [ProductID] = @New_ProductID WHERE [OrderID] = @OrderID AND [ProductID] = @ProductID">
        <DeleteParameters>
            <asp:Parameter Name="OrderID" Type="Int32" />
            <asp:Parameter Name="ProductID" Type="Int32" />
        </DeleteParameters>
        <UpdateParameters>
            <asp:Parameter Name="UnitPrice" Type="Decimal" />
            <asp:Parameter Name="Quantity" Type="Int16" />
            <asp:Parameter Name="Discount" Type="Single" />
            <asp:Parameter Name="OrderID" Type="Int32" />
            <asp:Parameter Name="ProductID" Type="Int32" />
            <asp:ControlParameter Name="New_ProductID" Type="Int32" ControlID="GridView1$ctl03$DropDownList2" PropertyName="SelectedValue" />
        </UpdateParameters>
        <InsertParameters>
            <asp:Parameter Name="OrderID" Type="Int32" />
            <asp:Parameter Name="ProductID" Type="Int32" />
            <asp:Parameter Name="UnitPrice" Type="Decimal" />
            <asp:Parameter Name="Quantity" Type="Int16" />
            <asp:Parameter Name="Discount" Type="Single" />
        </InsertParameters>
    </asp:SqlDataSource>
    </form>
</body>
</html>

.cs如下


using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Data;

public partial class _Default : System.Web.UI.Page 
{
    protected void Page_Load(object sender, EventArgs e)
    {
        
    }

    protected string Bind_ProductID(DropDownList DropDownList_ProductID)
    {
        string Result;
        
        GridViewRow GridViewRow_1 = (GridViewRow)DropDownList_ProductID.NamingContainer;
        if (GridViewRow_1.DataItem == null)
        {
            Result = "-1";
        }
        else
        {
            DataRowView DataRowView_1 = (DataRowView)GridViewRow_1.DataItem;
            Result = DataRowView_1["ProductID"].ToString();
        }
        return Result;
    }

    protected void GridView1_RowUpdated(object sender, GridViewUpdatedEventArgs e)
    {
        if (e.Exception != null)
        {
            e.ExceptionHandled = true;
            e.KeepInEditMode = true;
            Response.Write("");
        }
    }
}

過程中遇到的錯誤:

原本想法:

<asp:DropDownList ID="DropDownList2" runat="server" DataSourceID="SqlDataSource2"
                                DataTextField="ProductName" DataValueField="ProductID" SelectedValue='<%# Bind("ProductID") %>'>
                            </asp:DropDownList>

導致錯誤:

諸如 Eval()、XPath() 和 Bind() 等資料繫結方法,只能在資料繫結控制項的內容中使用。
'DropDownList2' 擁有的 SelectedValue 無效,因為它不在項目清單中。
參數名稱: value

替代方式:

<asp:DropDownList ID="DropDownList2" runat="server" DataSourceID="SqlDataSource2"
                                DataTextField="ProductName" DataValueField="ProductID" SelectedValue='<%# Bind_ProductID(DropDownList2) %>'>
                            </asp:DropDownList>

 

原本想法:

protected string Bind_ProductID(DropDownList DropDownList_ProductID)
    {
        string Result;
        
        GridViewRow GridViewRow_1 = (GridViewRow)DropDownList_ProductID.NamingContainer;
        DataRowView DataRowView_1 = (DataRowView)GridViewRow_1.DataItem;
        Result = DataRowView_1["ProductID"].ToString();
        return Result;
    }

導致錯誤(在選擇CategoryName時):

和另一種錯誤

[ArgumentOutOfRangeException: 'DropDownList2' 擁有的 SelectedValue 無效,因為它不在項目清單中。
參數名稱: value]

替代方式:

將DropDownList2(ProductID)的資料來源總有一個"-1"的選項

SelectCommand="select ProductID,ProductName from Products WHERE ([CategoryID] = @CategoryID)  union select -1 as ProductID,'' as ProductName from Products order by ProductName"

然後發現在選擇CategoryName時,GridViewRow_1.DataItem 是 null,於是利用這個現象將程式修改成

protected string Bind_ProductID(DropDownList DropDownList_ProductID)
    {
        string Result;
        
        GridViewRow GridViewRow_1 = (GridViewRow)DropDownList_ProductID.NamingContainer;
        if (GridViewRow_1.DataItem == null)
        {
            Result = "-1";
        }
        else
        {
            DataRowView DataRowView_1 = (DataRowView)GridViewRow_1.DataItem;
            Result = DataRowView_1["ProductID"].ToString();
        }
        return Result;
    }

 

原本想法:

<asp:ControlParameter Name="New_ProductID" Type="Int32" ControlID="DropDownList2" PropertyName="SelectedValue" />

導致錯誤:

在 ControlParameter 'New_ProductID' 中找不到控制項 'DropDownList2'。

替代方式(在瀏覽端程式查看DropDownList2的Name):

<asp:ControlParameter Name="New_ProductID" Type="Int32" ControlID="GridView1$ctl03$DropDownList2" PropertyName="SelectedValue" />