asp.net 如何根据一个下拉列表中的选择从另一个下拉列表中删除一个值?

64jmpszr  于 2023-05-23  发布在  .NET
关注(0)|答案(1)|浏览(121)

为了比标题更有描述性,我在www.example.com中有一系列下拉列表asp.net,它们都填充了来自同一过程的相同值。我试图找出一种方法来删除值从后续的下拉列表中,如果该值已经被选中在以前的列表。例如,如果用户在“ddl 1”中选择“Value 1”,则“Value 1”不应出现在“ddl 2”或任何其他后续列表(ddl 3,ddl 4等...)中。
下拉列表:

<td>
                    <asp:DropDownList ID="ddlEquipmentType1" runat="server" AppendDataBoundItems="true" AutoPostBack="true" Width="200px" />
                    <asp:TextBox runat="server" name="txtIndoorUnit1SerialNumber" Placeholder="Serial #" MaxLength="20" ID="txtIndoorUnit1SerialNumber" Style="width: 200px;" errorName="<%$ Resources:Locale, Global_IndoorUnit1SerialNumber%>" />
                    <span runat="server" id="vldReqIndoorUnit1SerialNumber" style="color: Red;" Visible="False">*</span>
                </td>
            </tr>
            <tr id="trIndoorUnit2SerialNumber" runat="server" visible="false">
                <td style="vertical-align:top">
                    <asp:label runat="server" id="Label30" Text="<%$ Resources:Locale, Global_IndoorUnit2SerialNumber%>" />
                </td>
                <td>
                    <asp:DropDownList ID="ddlEquipmentType2" runat="server" AppendDataBoundItems="true" AutoPostBack="true" Width="200px" />
                    <asp:TextBox runat="server" name="txtIndoorUnit2SerialNumber" Placeholder="Serial #" MaxLength="20" ID="txtIndoorUnit2SerialNumber" Style="width: 200px;" errorName="<%$ Resources:Locale, Global_IndoorUnit2SerialNumber%>" />
                    <span runat="server" id="vldReqIndoorUnit2SerialNumber" style="color: Red;" Visible="False">*</span>
                </td>
            </tr>

(还有更多,但这是他们都是如何设置的)
填充程序:

Protected Sub PopEquipmentDDLs()
    Dim dt As DataTable = New DataTable
    Dim strSQL As String = "SELECT RecID, EquipmentType FROM EquipmentTypes WHERE RecID IN (SELECT PrimaryEType FROM ETRelationship WHERE RecID = @RecID UNION ALL SELECT AccessoryEType1 FROM ETRelationship WHERE RecID = @RecID UNION ALL SELECT AccessoryEType2 FROM ETRelationship WHERE RecID = @RecID UNION ALL SELECT AccessoryEType3 FROM ETRelationship WHERE RecID = @RecID UNION ALL SELECT AccessoryEType4 FROM ETRelationship WHERE RecID = @RecID UNION ALL SELECT AccessoryEType5 FROM ETRelationship WHERE RecID = @RecID UNION ALL SELECT AccessoryEType6 FROM ETRelationship WHERE RecID = @RecID UNION ALL SELECT AccessoryEType7 FROM ETRelationship WHERE RecID = @RecID UNION ALL SELECT AccessoryEType8 FROM ETRelationship WHERE RecID = @RecID UNION ALL SELECT AccessoryEType9 FROM ETRelationship WHERE RecID = @RecID) AND EquipmentType <> @PEquipmentType"
    Dim ddlCollection As New List(Of DropDownList)() From {ddlEquipmentType1, ddlEquipmentType2, ddlEquipmentType3, ddlEquipmentType4, ddlEquipmentType5, ddlEquipmentType6, ddlEquipmentType7, ddlEquipmentType8, ddlEquipmentType9}
    Dim selectedValues As New Dictionary(Of Integer, String)()

    'For i As Integer = 0 To ddlCollection.Count - 1
    '    Dim ddl As DropDownList = ddlCollection(i)
    '    If ddl.SelectedIndex > 0 Then
    '        selectedValues.Add(i, ddl.SelectedItem.Value)
    '    End If
    'Next

    Using conn As New SqlConnection(ConfigurationManager.ConnectionStrings("WillisConnectionString").ToString)
        Using cmdSQL As New SqlCommand(strSQL, conn)
            cmdSQL.Parameters.Add("RecID", SqlDbType.Int).Value = ddlNbZones.SelectedValue
            cmdSQL.Parameters.Add("PEquipmentType", SqlDbType.VarChar).Value = txtEType.Text
            conn.Open()
            dt.Load(cmdSQL.ExecuteReader())

            'Clear all drop-down lists
            For Each ddl As DropDownList In ddlCollection
                ddl.Items.Clear()
                ddl.Items.Add(New ListItem("---SELECT EQUIPMENT---", "0"))
            Next

            'populate drop-downs
            For i As Integer = 0 To ddlCollection.Count - 1
                Dim ddl As DropDownList = ddlCollection(i)

                ddl.DataSource = dt
                ddl.DataTextField = "EquipmentType"
                ddl.DataValueField = "RecID"
                ddl.DataBind()

                'If selectedValues.ContainsKey(i) Then
                '    ddl.SelectedValue = selectedValues(i)
                'End If
            Next

            For Each item In ddlEquipmentType2.Items
                System.Diagnostics.Debug.WriteLine(item)
            Next
        End Using
    End Using
End Sub

过滤程序:

Private Sub FilterDDLs(ByVal ddlCollection As List(Of DropDownList))
    For i As Integer = 0 To ddlCollection.Count - 2
        Dim ddl As DropDownList = ddlCollection(i)

        ' Skip filtering if selected index is 0
        If ddl.SelectedIndex > 0 Then
            Dim selectedItemText As String = ddl.SelectedItem.Text

            For j As Integer = i + 1 To ddlCollection.Count - 1
                Dim subsequentDDL As DropDownList = ddlCollection(j)

                Dim itemToRemove As ListItem = subsequentDDL.Items.FindByText(selectedItemText)
                If itemToRemove IsNot Nothing Then
                    subsequentDDL.Items.Remove(itemToRemove)
                End If
            Next
        End If
    Next
End Sub

我从下拉列表的databinding事件调用过滤器过程,它循环通过所有列表并尝试根据匹配的文本删除项目,我也尝试根据选定的值删除它们,因为它们都是相同的值。
如果我删除“If ddl.SelectedIndex > 0 Then”,并且不查找索引大于0的ddl,它将删除我在填充过程中添加的值(0)处的ListItem,但无论出于什么原因,我无法让它删除值1+。
我不确定我是否在错误的地方调用了这个函数,但是我尝试在“selectedIndexChanged”事件中调用过滤器过程也没有用。
我还尝试在填充过程中过滤列表,然后在每个“selectedIndexChanged”事件中调用pop过程,而不是为它设置一个单独的过程。因此,注解代码将选定的值存储在字典中,然后在事后重新分配它们。
任何有关此问题的帮助将不胜感激。

gk7wooem

gk7wooem1#

好吧,那么说这个标记:
我将使用一个列表框,但列表框的“事件”模型与组合框(下拉列表)100%相同,并且此代码可以与列表框或DropDownList互换。
因此,标记:
让我们在页面上删除3个列表框。
例如:

<asp:ListBox ID="ListBox1" runat="server"
            style="float:left"
            DataValueField="ID"
            DataTextField="HotelName"
            OnSelectedIndexChanged="ListBox1_SelectedIndexChanged"
            Height="220px" Width="230"
            AutoPostBack="true"
            SelectionMode="Multiple"
        >
        </asp:ListBox>

        <asp:ListBox ID="ListBox2" runat="server"
            style="float:left;margin-left:20px"
            DataValueField="ID"
            DataTextField="HotelName"
            OnSelectedIndexChanged="ListBox2_SelectedIndexChanged"
            Height="220px" Width="230"
            AutoPostBack="true"
            SelectionMode="Multiple"
        >
        </asp:ListBox>

        <asp:ListBox ID="ListBox3" runat="server"
            style="float:left;margin-left:20px"
            DataValueField="ID"
            DataTextField="HotelName" 
            Height="220px" Width="230"
            SelectionMode="Multiple"
        >
        </asp:ListBox>

要加载的代码:

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

    If Not IsPostBack Then
        LoadCombo
    End If
End Sub

Sub LoadCombo()

    Dim strSQL As String =
        "SELECT ID, HotelName FROM tblHotelsA ORDER BY HotelName"
    Dim rstHotels As DataTable
    rstHotels = MyRst(strSQL)

    ListBox1.DataSource = rstHotels
    ListBox1.DataBind()

    ListBox2.DataSource = rstHotels
    ListBox2.DataBind()

    ListBox3.DataSource = rstHotels
    ListBox3.DataBind()

End Sub

级联码-我们只需要lb 1和lb 2。
因此,这段代码:

Protected Sub ListBox1_SelectedIndexChanged(sender As Object, e As EventArgs)

    Cascade()

End Sub

Protected Sub ListBox2_SelectedIndexChanged(sender As Object, e As EventArgs)
    Cascade(2)
End Sub

Sub Cascade(Optional lbStart As Integer = 1)

    ' remove all/any selected in 1 from 2
    If lbStart < 2 Then
        ListBox2.Items.Clear()
        For Each LB1 As ListItem In ListBox1.Items
            If Not LB1.Selected Then
                Dim nItem As New ListItem(LB1.Text, LB1.Value)
                ListBox2.Items.Add(nItem)
            End If
        Next
    End If

    ' now remove any selected in 2 from 3

    ListBox3.Items.Clear()
    For Each LB2 As ListItem In ListBox2.Items
        If Not LB2.Selected Then
            Dim nItem As New ListItem(LB2.Text, LB2.Value)
            ListBox3.Items.Add(nItem)
        End If
    Next

End Sub

我们现在看到/得到这个:

当然,现在我使用了一个helper例程来加载sql(只返回一个数据表)。这是从我的全球handy花花公子助手例程。(并且对于上面的代码示例并不重要,但是我在这里仅供参考

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)
            rstData.TableName = strSQL
        End Using
    End Using
    Return rstData
End Function

编辑:对于怀疑论者,以上为下拉列表。

因此,采用现有的标记,更改为下拉列表

<asp:DropDownList ID="ListBox1" runat="server"
            style="float:left"
            DataValueField="ID"
            DataTextField="HotelName"
            OnSelectedIndexChanged="ListBox1_SelectedIndexChanged"
            Width="230"
            AutoPostBack="true"
        >
        </asp:DropDownList>

        <asp:DropDownList ID="ListBox2" runat="server"
            style="float:left;margin-left:20px"
            DataValueField="ID"
            DataTextField="HotelName"
            OnSelectedIndexChanged="ListBox2_SelectedIndexChanged"
            Width="230"
            AutoPostBack="true"
        >
        </asp:DropDownList>

        <asp:DropDownList ID="ListBox3" runat="server"
            style="float:left;margin-left:20px"
            DataValueField="ID"
            DataTextField="HotelName" 
            Width="230"
        >
        </asp:DropDownList>

所以,codebeath现在变成了这样:

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

    If Not IsPostBack Then
        LoadCombo
    End If

End Sub

Sub LoadCombo()

    Dim strSQL As String =
        "SELECT ID, HotelName FROM tblHotelsA ORDER BY HotelName"
    Dim rstHotels As DataTable
    rstHotels = MyRst(strSQL)

    ListBox1.DataSource = rstHotels
    ListBox1.DataBind()
    ListBox1.Items.Insert(0, New ListItem("Please Select"))

    'ListBox2.DataSource = rstHotels
    'ListBox2.DataBind()

    'ListBox3.DataSource = rstHotels
    'ListBox3.DataBind()

End Sub

Protected Sub ListBox1_SelectedIndexChanged(sender As Object, e As EventArgs)
    Cascade()
End Sub

Protected Sub ListBox2_SelectedIndexChanged(sender As Object, e As EventArgs)
    Cascade(2)
End Sub

Sub Cascade(Optional lbStart As Integer = 1)

    ' remove all/any selected in 1 from 2
    If lbStart < 2 Then
        ListBox2.Items.Clear()
        For Each LB1 As ListItem In ListBox1.Items
            If Not LB1.Selected Then
                Dim nItem As New ListItem(LB1.Text, LB1.Value)
                ListBox2.Items.Add(nItem)
            End If
        Next
    End If

    'Now remove any selected in 2 from 3

    ListBox3.Items.Clear()
    For Each LB2 As ListItem In ListBox2.Items
        If Not LB2.Selected Then
            Dim nItem As New ListItem(LB2.Text, LB2.Value)
            ListBox3.Items.Add(nItem)
        End If
    Next

End Sub

现在我们看到/得到这个:

当然,这回避了一个问题,为什么不使用一个列表框与selectmode=“multiple”。
列表框唯一真实的的缺点是,用户通常不知道您可以按住CTRL键来选择多个项目,因此,这确实需要键盘+鼠标操作。

相关问题