动态添加下拉列表并通过回发记住它们

时间:2009-08-10 17:16:23

标签: asp.net vb.net

我正在努力找出实现这一目标的最佳方法:

我需要在页面加载时显示下拉列表,默认选择的值为空,或者为空元素(例如“ - ”)。当用户从列表中选择一个值时,另一个下拉列表将添加到第一个下面,依此类推。

我的问题是如何使页面记住通过回发创建的下拉列表及其选择的值?我是否必须使用某种数组来存储它们?

非常感谢。

编辑:我做了这个例子,动态添加下拉列表并将它们保存到事件处理程序,但事件不会触发。

编辑2:更改了代码,因为我标记为VB.Net并在C#中发布了一些内容。我通过一些微不足道的改进来更新代码,但仍然不会触发事件:(

    Private myDdlArray As New List(Of DropDownList)

Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

    If (Session("ddl") Is Nothing) Then
        Session("ddl") = myDdlArray
    End If

    If (Session("ddlcount") Is Nothing) Then
        Session("ddlcount") = 0
    End If

    myDdlArray = CType(Session("ddl"), List(Of DropDownList))

    Dim myDdl As New DropDownList
    myDdl = New DropDownList
    For Each myDdl In myDdlArray
        panel.Controls.Add(myDdl)
        panel.Controls.Add(New LiteralControl("<br/>"))
    Next

    Session("ddl") = myDdlArray

End Sub

Protected Sub btn_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btn.Click

    myDdlArray = CType(Session("ddl"), List(Of DropDownList))
    Dim ddlCount As Integer = CInt(Session("ddlcount")) + 1

    Dim newDdl As New DropDownList
    newDdl.ID = String.Format("ddlNPKMaterial{0}", ddlCount)
    newDdl.AutoPostBack = True

    AddHandler newDdl.SelectedIndexChanged, AddressOf cbo_SelectedIndexChanged

    newDdl.Items.Add("Uno")
    newDdl.Items.Add("Dos")
    newDdl.Items.Add("Tres")

    myDdlArray.Add(newDdl)

    panel.Controls.Clear()

    Dim myDdl As New DropDownList
    myDdl = New DropDownList
    For Each myDdl In myDdlArray
        panel.Controls.Add(myDdl)
        panel.Controls.Add(New LiteralControl("<br/>"))
    Next

    Session("ddl") = myDdlArray
    Session("ddlcount") = ddlCount + 1

End Sub

Protected Sub btnReset_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnReset.Click

    Session("ddl") = Nothing
    Session("ddlcount") = Nothing

End Sub

Protected Sub btnShow_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnShow.Click

    ' Insert brain here

End Sub

Public Sub cbo_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs)

    Response.Write(CType(sender, DropDownList).ID)

End Sub

Protected Sub Page_PreRender(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.PreRender

    If (Session("ddl") Is Nothing) Then
        panel.Controls.Clear()
    End If

End Sub

在aspx中我有:

<form id="form1" runat="server">
<div>
    <asp:Button ID="btn" runat="server" Text="Add" />
    <asp:Button runat="server" ID="btnShow" Text="Tell me" />
    <asp:Button runat="server" ID="btnReset" Text="Reset" />
    <br />
    <asp:Panel runat="server" ID="panel">
        <asp:GridView runat="server" ID="grd">
            <Columns>
                <asp:BoundField HeaderText="Id" DataField="Id" />
            </Columns>
        </asp:GridView>
    </asp:Panel>
</div>
</form>

4 个答案:

答案 0 :(得分:1)

你可以简单地在你的asp代码中存在两个下拉列表,在第一页加载时只有一个可见。所以......就像......

<asp:DropDownList ID="mainDDL" Visible="true" runat="server">
    <asp:ListItem  Text="Elements here" Value="0" />
    <asp:ListItem Text="More elements" Value="1" />
</asp:DropDownList>

<asp:DropDownList ID="dynamicDDL" Visible="false" runat="server">
    <asp:ListItem Text="This is an element of the dynamic DDL" Value="3" />
</asp:DropDownList> 

然后,当选择“更多元素”项时,将dynamicDDL的可见性切换为true。

然后在每个回发上,在Page_Load事件上,检查mainDDL的值是什么。如果为0,则将dynamicDDL设置为visible = true

修改

好的,我接受了这个。然而,在这方面取得了一些进展,也许它会引导我们找到一些线索。

首先,我们需要一个数组来存储它。我们需要一个静态的DDL数组和一个静态整数来计算我们的元素。这些可以定义为......

Private Shared ddl_arr As DropDownList() = New DropDownList(100) {} 'max, 100 ddls.
Private Shared ddl_count As Integer = 0

现在,我们需要一个面板来存储我们的DDL。这是一个简单的asp脚本,例如......

<asp:Panel ID="parentPanel" runat="server">
    <asp:DropDownList ID="mainDDL" AutoPostBack="true" Visible="true" runat="server">
        <asp:ListItem  Text="Elements here" Value="0" />
        <asp:ListItem Text="More elements" Value="1" />
    </asp:DropDownList>
</asp:Panel>

现在,在我们的页面加载中,我们将要加载到目前为止已保存的任何下拉列表。这可以用诸如......的方式编码。

Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
    Try
        If TypeOf ddl_arr(0) Is DropDownList Then
            For Each ddl As DropDownList In ddl_arr
                add_ddl(ddl)
            Next
        End If
    Catch ex As Exception ' this is a bad idea, but for brevity..
    End Try
End Sub

我们的add_ddl方法只会将新的下拉列表添加到parentPanel。

Protected Sub add_ddl(ByVal ddl As DropDownList)
    Try
        parentPanel.Controls.Add(ddl)
        'add any formatting you would like after each ddl here.
    Catch ex As Exception
    End Try
End Sub

最后,我们改变ddl时的方法。这会创建一个全新的ddl,给它一个id(以及你可能需要的任何属性),将它添加到数组中,递增我们的计数器,并将其添加到页面中。

Protected Sub mainDDL_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles mainDDL.SelectedIndexChanged
    Dim newDDL As DropDownList = New DropDownList()
    newDDL.ID = "ddlID" & ddl_count 'we will need to store a new ID for each one.  So, dynamically generate this.
    'continue to add properties to your ddl in this fashion...
    ddl_arr(ddl_count) = newDDL
    ddl_count = ddl_count + 1
    add_ddl(newDDL)
End Sub

这个方法应该检查数组的结尾(除其他外),但让我们保持简单。只要更改ORIGINAL DDL的索引,此代码将仅添加新的DDL。每当所选的索引更改为所有这些新制作的DDL时,您将需要设置每个新创建的DDL以具有一个方法(执行上述指令)。

希望这能让你朝着正确的方向前进。这比我希望的那样有条不紊,对不起!

答案 1 :(得分:1)

我将使用OnLoad重新创建控件,但是如果你没有在ViewState中存储控件数(你可以将它放入Session,HiddenField,Cookie等),那么你可以做它在OnInit。无论哪种方式都应该触发回发事件。

<asp:PlaceHolder id="phDdl" runat="server">
    <asp:DropDwonList id="ddl" runat="server" 
     OnSelectedIndexChanged="ddl_SelectedIndexChanged" />
</asp:PlaceHolder>

<script runat="server">
    int DdlIndex {
       get { 
          object o = ViewState["_ddlIndex"];
          if (o == null) {
             ViewState["_ddlIndex"] = 0;
          }
          return (int)ViewState["_ddlIndex"];
       }
       set {
          ViewState["_ddlIndex"] = value;
       }
    }

    protected override void OnLoad(EventArgs e) {
       base.OnLoad(e);
       for (int i = 0; i < DdlIndex; i++) {
          AddDropDownList(i);
       }
    }

    void ddl_SelectedIndexChanged(object sender, EventArgs e) {
       var ddl = (DropDownList)sender;
       if (ddl.SelectedIndex > 0) {
          AddDropDownList(DdlIndex++);
       }
    }

    void AddDropDownList(int i) {
       var ddl = new DropDownList();
       ddl.Id = string.Format("ddl{0}", i);
       ddl.SelectedIndexChanged += ddl_SelectedIndexChanged;
       // add items
       phDdls.Add(ddl);
    }
</script>

答案 2 :(得分:1)

创建动态控件非常棘手。我会从reading this开始。

答案 3 :(得分:0)

在Page_Init方法中创建并添加下拉列表,并根据您收集的后备数据生成名称。从它们获取输入时,使用FindControl()方法从页面读取它们的返回值,或者从Request.Form []获取控件的返回值。 FindControl使用控件的id,Requst.Name使用客户端ID - 您可以使用与生成名称相同的函数来获取此信息。

总的来说,ASP.NET并不擅长使用生成的控件,但是通过将您在模型或数据结构中使用的数据与正在生成的控件分开来保存并不困难。控件并检索结果。