【问题标题】:Could not find control 'DropCity' in ControlParameter 'City' ERROR在 ControlParameter 'City' 错误中找不到控件 'DropCity'
【发布时间】:2021-12-26 22:59:17
【问题描述】:

上下文:我试图在 gridview 中嵌套两个下拉列表(ddl),第一个 ddl 称为“Ciudad”,第二个称为“Comuna”,我希望根据“Ciudad”选择“ Comunas”更改为相应的“ciudad”。但我得到一个错误,我无法解决它。

我的 GridView:

       <asp:GridView ID="GridLectores" runat="server" AllowPaging="True" DataKeyNames="CODLIB,PAR_COD_PAR" CssClass="gridview" Style="margin-left: 100px" AllowSorting="True" AutoGenerateColumns="False" CellPadding="0" DataSourceID="SqlDataSource1" ForeColor="#333333" GridLines="Horizontal" PageSize="5" Width="50%" Height="270px" HorizontalAlign="Center" CellSpacing="1" OnRowUpdating="Actualizar_Lectores" OnRowDeleting="Borrar_Lector" OnRowDataBound="GridLectores_RowDataBound">
           <AlternatingRowStyle BackColor="White" ForeColor="#284775" />
           <Columns>
               <asp:TemplateField HeaderText="Ciudad" SortExpression="Ciudad">
                   <EditItemTemplate>
                       <asp:DropDownList ID="DropCiudad" runat="server" DataSourceID="SqlDataSourceCiudad" DataValueField="PAR_COD_PAR" DataTextField="PAR_DES_PAR"></asp:DropDownList>
                   </EditItemTemplate>
                   <ItemTemplate>
                       <asp:Label ID="Label11" runat="server" Text='<%# Bind("Ciudad") %>'></asp:Label>
                   </ItemTemplate>
               </asp:TemplateField>
               <asp:TemplateField HeaderText="Comuna" SortExpression="Comuna">
                   <EditItemTemplate>
                       <asp:DropDownList ID="DropComuna" runat="server" DataSourceID="SqlDataSourceComuna" DataValueField="PAR_COD_PAR" DataTextField="PAR_DES_PAR"></asp:DropDownList>
                   </EditItemTemplate>
                   <ItemTemplate>
                       <asp:Label ID="Label10" runat="server" Text='<%# Bind("Comuna") %>'></asp:Label>
                   </ItemTemplate>
               </asp:TemplateField>
               <asp:TemplateField HeaderText="Estado" SortExpression="Estado">
                   <EditItemTemplate>
                       <asp:DropDownList ID="DropEstado" runat="server" DataSourceID="SqlDataSourceEstado" DataValueField="PAR_COD_PAR" DataTextField="PAR_DES_PAR"></asp:DropDownList>
                   </EditItemTemplate>
                   <ItemTemplate>
                       <asp:Label ID="Label12" runat="server" Text='<%# Bind("Estado") %>'></asp:Label>
                   </ItemTemplate>
               </asp:TemplateField>
               <asp:TemplateField HeaderText="Seleccione">
                   <EditItemTemplate>
                       <asp:Button ID="btnupdate" class="btn btn-info" runat="server" CausesValidation="True" CommandName="Update"
                           Text="Actualizar" Style="padding: 3px 3px 3px 3px"></asp:Button>
                       <asp:Button ID="btnborrar" class="btn btn-danger" runat="server" CausesValidation="True" CommandName="Delete"
                           Text="Borrar" Style="padding: 3px 3px 3px 3px"></asp:Button>
                       <asp:LinkButton ID="btncancelar" runat="server" CausesValidation="False" CommandName="Cancel"
                           Text="Cancelar" CssClass="BotonRojo" Style="padding: 3px 3px 3px 3px; margin-top: 3px"></asp:LinkButton>
                   </EditItemTemplate>
                   <ItemTemplate>
                       <asp:LinkButton ID="btnedit" class="btn btn-primary" runat="server" CausesValidation="False" CommandName="Edit"
                           Text="Editar" Style="padding: 3px 3px 3px 3px"></asp:LinkButton>
                   </ItemTemplate>
               </asp:TemplateField>
           </Columns>
       </asp:GridView>

我的 SqlDataSource 的:

        <asp:SqlDataSource ID="SqlDataSourceComuna" runat="server" ConnectionString="<%$ ConnectionStrings:CadenaConexion %>" SelectCommand="SELECT par_cod_par, par_des_par, par_cod_aux FROM PAR WHERE (par_cod_tab = 2) AND (par_cod_aux = @Ciudad)">
            <SelectParameters>
                <asp:ControlParameter ControlID="DropCiudad" PropertyName="SelectedValue" DefaultValue="0" Name="Ciudad"></asp:ControlParameter>
            </SelectParameters>
        </asp:SqlDataSource>
        <asp:SqlDataSource ID="SqlDataSourceCiudad" runat="server" ConnectionString="<%$ ConnectionStrings:CadenaConexion %>" SelectCommand="SELECT par_cod_tab, par_cod_par, par_des_par FROM PAR WHERE (par_cod_tab = 4) ORDER BY PAR_COD_PAR ASC"></asp:SqlDataSource>

【问题讨论】:

    标签: sql asp.net sql-server sqldatasource


    【解决方案1】:

    这可能是一个挑战 - 原因是列表中的一个组合框未绑定,并且在数据库中不存在。它只是数据库中存在的级联组合的过滤器。

    所以,你可以这样做。我们将假设一个人,他们想选择一家酒店,但我们提供了一个“过滤器”/级联组合。我们允许用户选择一个城市,然后仅限该城市的酒店。

    所以,我们的标记可以是这样的。一个 cbo 是城市过滤器,然后实际数据值 (hotel_id) 是数据的一部分 - 但如上所述的城市 cbo 只是一个过滤器。

    所以,这个标记:

    <asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False"
        DataKeyNames="ID" 
        CssClass="table"
        Width="30%"
        >
        <Columns>
            <asp:BoundField DataField="Firstname" HeaderText="Firstname" />
            <asp:BoundField DataField="LastName" HeaderText="LastName"  />
            <asp:BoundField DataField="City" HeaderText="City" />
    
            <asp:TemplateField HeaderText="Select Hotel City">
                <ItemTemplate>
                    <asp:DropDownList ID="cboCity" runat="server" Width="120px"
                        DataTextField = "City"
                        DataValueField = "City"> 
                    </asp:DropDownList>
                </ItemTemplate>
            </asp:TemplateField>
    
            <asp:TemplateField HeaderText="Select Hotel">
                <ItemTemplate>
                    <asp:DropDownList ID="cboHotels" runat="server" Width="210px"
                        DataValueField ="ID"
                        DataTextField ="HotelName"
                        ></asp:DropDownList>
                </ItemTemplate>
            </asp:TemplateField>
        </Columns>
    </asp:GridView>
    

    好的,现在我们的代码来加载网格。

    Dim rstCity As New DataTable
    
    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
    
        If Not IsPostBack Then
            LoadGrid
        End If
    
    
    End Sub
    
    Sub LoadGrid()
    
        ' load up City list for combo box
        rstCity = MyRst("SELECT City from City ORDER BY City")
    
        ' load up the grid
        GridView1.DataSource = MyRst("SELECT * from People ORDER BY FirstName")
        GridView1.DataBind()
    
    End Sub
    

    注意关闭我在类级别声明 rstCity - 它会在数据绑定过程中持续存在(让我们不必一遍又一遍地重新拉出城市组合列表)。

    到目前为止,很容易。但是我们现在必须对每一行执行以下操作:

    Load up the city cbo box
    Load up the hotel select cbo box
    
    but also set the city cbo box to the city that we filtered to.
    

    所以,这是一段代码,但看起来像这样:

    Protected Sub GridView1_RowDataBound(sender As Object, e As GridViewRowEventArgs) Handles GridView1.RowDataBound
    
        If e.Row.RowType = DataControlRowType.DataRow Then
    
            ' get the data bind row data
            Dim gData As DataRowView = e.Row.DataItem
            ' load the city combo box
    
            Dim cboCity As DropDownList = e.Row.FindControl("cboCity")
            cboCity.DataSource = rstCity
            cboCity.DataBind()
            ' add blank row for city
            cboCity.Items.Insert(0, New ListItem("", ""))
    
            ' now load Hotel combo box (if we have one!!)
            Dim cboHotels As DropDownList = e.Row.FindControl("cboHotels")
    
            If Not IsDBNull(gData("Hotel_id")) Then
    
                ' get the one hotel reocrd - we need the city from that hotel
                ' to set the city cbo - that city cbo is NOT in the People databse - only a filter
    
                Dim rstOneHotel As DataRow = MyRst("SELECT * From tblHotels where ID = " & gData("Hotel_id")).Rows(0)
                Dim strHotelCity As String = rstOneHotel("City")
    
                ' set the city filter cbo to correct city
                cboCity.SelectedValue = strHotelCity
    
                ' load hotel combo box only with current city list
                Dim strSQL As String = "Select ID,HotelName From tblHotels WHERE City = '" &
                                        strHotelCity & "' ORDER BY HotelName"
                cboHotels.DataSource = MyRst(strSQL)
                cboHotels.DataBind()
                ' set hotels combo to current selected
                cboHotels.SelectedValue = gData("Hotel_id")
            End If
    
        End If
    
    End Sub
    

    现在我们看到了:

    现在,上面当然是基于每一行“hotel_id”。

    但是,我们确实需要连接城市过滤器并级联到酒店。

    所以,我们需要向 cboCity 添加一个事件。

    所以,我们这样做:

    由于 cbo 框在网格内部,我们不能使用属性表,但如上所示,我们只需开始输入标记。 intel-sense 将提示创建新事件 - 看起来没有发生任何事情,但是当我们返回到后面的代码时,代码存根将存在。当然,我们还必须设置 autopostback=true。

    好的,所以这个级联代码与我们在数据绑定例程中所做的非常相似。当然,当用户选择一个新城市时,我们确实必须吹掉现有值,因为过滤器是针对不同城市的。

    这段代码是这样的:

    Protected Sub cboCity_SelectedIndexChanged(sender As Object, e As EventArgs)
    
        Dim cboCity As DropDownList = sender
    
        ' get current grid row
        Dim gRow As GridViewRow = cboCity.Parent.Parent
    
        ' filter hotels to current city
        Dim strCity As String = cboCity.SelectedItem.Text
    
        Dim strSQL = "SELECT * from tblHotels WHERE CITY = '" & strCity & "' ORDER BY HotelName"
        Dim cboHotels As DropDownList = gRow.FindControl("cboHotels")
        cboHotels.DataSource = MyRst(strSQL)
        cboHotels.DataBind()
        cboHotels.Items.Insert(0, New ListItem("", ""))
        ' blow out the current hotel id
        Dim MyHotelID As HiddenField = gRow.FindControl("HotelID")
        MyHotelID.Value = ""
    
    End Sub
    

    现在我们确实有一个地方可以连接城市输入。既然确实来自cbo box,那么sql注入的风险就很低了。但如果你真的在这个问题上坚持,那么我们可以参数化那段代码。

    另外,我使用了一个返回数据表的辅助例程,代码是这样的:

    Public Function MyRst(strSQL As String) As DataTable
    
        Dim rstData As New DataTable
    
        Using conn As New SqlConnection(My.Settings.TEST4)
            Using cmdSQL As New SqlCommand(strSQL, conn)
                conn.Open()
                rstData.Load(cmdSQL.ExecuteReader)
            End Using
        End Using
    
        Return rstData
    
    End Function
    

    编辑:

    发帖人指出他们正在寻找 C# 版本。我对这两种语言都很流利 - 但 vb 代码更省力,因为 vb 为你做了很多自动转换。

    然而,归根结底,这里的概念和你如何解决这个问题才是这里真正的价值。

    但是,为了更好的衡量,这里是 C# 代码

    加载网格的代码:

        DataTable rstCity = new DataTable();
        protected void Page_Load(object sender, EventArgs e)
        {
            if (!IsPostBack)
                LoadGrid();
        }
    
        void LoadGrid ()
        {
            // load up City list for combo box
            rstCity = MyRst("SELECT City from City ORDER BY City");
            // load up the grid
            GridView1.DataSource = MyRst("SELECT * from People ORDER BY FirstName");
            GridView1.DataBind();
        }
    

    现在是物品数据绑定事件:

       protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
        {
            if (e.Row.RowType == DataControlRowType.DataRow)
            {
    
    
                // get the data bind row data
                DataRowView gData = (DataRowView)e.Row.DataItem;
    
                // load the city combo box
    
                DropDownList cboCity = (DropDownList)e.Row.FindControl("cboCity");
                cboCity.DataSource = rstCity;
                cboCity.DataBind();
                // add blank row for city
                cboCity.Items.Insert(0, new ListItem("", ""));
    
                // now load Hotel combo box (if we have one!!)
                DropDownList cboHotels = (DropDownList)e.Row.FindControl("cboHotels");
    
                if (!DBNull.Value.Equals(gData["Hotel_id"]))
                {
                    // get the one hotel reocrd - we need the city from that hotel
                    // to set the city cbo - that city cbo is NOT in the People databse - only a filter
    
                    DataRow rstOneHotel = MyRst("SELECT * From tblHotels where ID = " + gData["Hotel_id"].ToString()).Rows[0];
                    string strHotelCity = rstOneHotel["City"].ToString();
    
                    // set the city filter cbo to correct city
                    cboCity.SelectedValue = strHotelCity;
    
                    // load hotel combo box only with current city list
                    string strSQL = @"Select ID,HotelName From tblHotels WHERE City = '" +
                                            strHotelCity + "' ORDER BY HotelName";
                    cboHotels.DataSource = MyRst(strSQL);
                    cboHotels.DataBind();
                    // set hotels combo to current selected
                    cboHotels.SelectedValue = gData["Hotel_id"].ToString();
                }
            }
        }
    

    当然还有网格的“级联”代码。虽然上面的内容是正确的,但我们仍然希望 cbo 能够正常工作。所以这个:

        protected void cboCity_SelectedIndexChanged(object sender, EventArgs e)
        {
            DropDownList cboCity = (DropDownList)sender;
    
            // get current grid row
            GridViewRow gRow = (GridViewRow)cboCity.Parent.Parent;
    
            // filter hotels to current city
            string strCity = cboCity.SelectedItem.Text;
    
            string strSQL = @"SELECT * from tblHotels WHERE CITY = '" + strCity + "' ORDER BY HotelName";
            DropDownList cboHotels = (DropDownList)gRow.FindControl("cboHotels");
            cboHotels.DataSource = MyRst(strSQL);
            cboHotels.DataBind();
            cboHotels.Items.Insert(0, new ListItem("", ""));
            // blow out the current hotel id
            HiddenField MyHotelID = (HiddenField)gRow.FindControl("HotelID");
            MyHotelID.Value = "";
        }
    

    当然还有我的“帮助”例程来返回一个表(一遍又一遍地写太累了!!!)。

    所以这个:

        public DataTable MyRst(string strSQL)
        {
            DataTable rstData = new DataTable();
            using (SqlConnection conn = new SqlConnection(Properties.Settings.Default.TEST4))
            {
                using (SqlCommand cmdSQL = new SqlCommand(strSQL, conn))
                {
                    conn.Open();
                    rstData.Load(cmdSQL.ExecuteReader());
                }
            }
            return rstData;
        }
    

    【讨论】:

    • 我很欣赏这些解释,但我没有使用 Visual Basic,也不太了解。
    • 归根结底,这是关于概念的更多信息。但是,您没有将其标记为 c#,因此我使用了 vb(它的工作量较小 - 因为 vb 为您执行了大量的自动转换)。但是,在 c# 中重新键入代码是一件容易和简单的事情 - 我更新了我的帖子,现在包含 c# 版本。
    猜你喜欢
    • 1970-01-01
    • 2014-10-12
    • 2023-03-17
    • 2012-11-16
    • 2012-05-28
    • 2012-08-08
    • 1970-01-01
    • 1970-01-01
    • 2016-10-08
    相关资源
    最近更新 更多