【问题标题】:Removing or disable ComboBox item which is selected in another list删除或禁用在另一个列表中选择的 ComboBox 项
【发布时间】:2016-01-16 14:58:41
【问题描述】:

我在WinForm 上有三个组合框,如下所示:

                  ___________________________
ComboBox List 1: |_______________________|___|
                  ___________________________
ComboBox List 2: |_______________________|___|
                  ___________________________
ComboBox List 3: |_______________________|___|

每个组合框在设计时都会有一个“A”、“B”、“C”的列表。

默认情况下,列表 1 是表单上唯一处于活动状态的表单,而列表 2 和列表 3 将在其前一个被选择时变为活动状态。

我想做的是,如果用户选择选项 C,我希望选项 C 不再可用于列表 2 和 3。

我知道这将涉及组合框的.SelectedIndexChanged 事件,但不知道从哪里开始编码。

我在 StackOverflow 上找到了以下答案,因为我是在设计时而不是通过文件导入来提供项目的,所以我的情况并不适用:vb.net change combobox options depending on selected item in 2 previous comboboxes

【问题讨论】:

    标签: vb.net winforms combobox


    【解决方案1】:

    这类似于史蒂夫的回答,但使用了DataSource。此外,没有真正需要Enable/Disable 每个 CBO。当他们进行更改时,先前的选择会从源中过滤掉。任何重复的“先前”更改都将被撤消。

    CBO1 总是有完整的列表,而其他的则省略了之前的选择。您不能以重复选择结束,因为重新选择 #2 与 #3 相同,会将 #3 的内容更改为列表中的第一个选项。

    ' the master list
    Private OptList As New List(Of String)
    Private ignore As Boolean
    
    ' initialize somewhere:
    OptList.AddRange(New String() {"Red", "Green", "Blue", "Violet", "Orange"})
    ' set up cbos
    ' ignore changes while setting up:
    ignore = True
    cb1.DataSource = OptList.ToArray
    cb1.SelectedIndex = -1
    cb2.DataSource = OptList.ToArray
    cb2.SelectedIndex = -1
    cb3.DataSource = OptList.ToArray
    cb3.SelectedIndex = -1
    ignore = False
    

    全部启用后,他们可以按任意顺序选择它们。

    Private Sub cbo_SelectedIndexChanged(sender As Object, e As EventArgs) _
                 Handles cb1.SelectedIndexChanged, cb2.SelectedIndexChanged
        If ignore Then Exit Sub
    
        Dim cbo = TryCast(sender, ComboBox)
        If cbo IsNot Nothing AndAlso cbo Is cb1 Then
            cb2.DataSource = GetFilteredList(New String() {cb1.Items(cb1.SelectedIndex)})
        Else
            cb3.DataSource = GetFilteredList(New String() {cb1.SelectedItem.ToString,
                                                       cb2.SelectedItem.ToString})
        End If
    End Sub
    
    Private Function GetFilteredList(items As String()) As String()
        Return OptList.Except(items).ToArray()
    End Function
    

    Since cbo3 is limited to those items not picked in #1 or #2 (a slave) you dont have to do anything when that selection changes.


    Could this be expanded to say 9 cbo by continuing multiple if/else statementsHow would I keep the first option. Say if I wanted to include a "None" option always available.

    那么多,我会做的更抽象。代码可能更难阅读/遵循,但它的数量更少(我使用的是 4 个 cbos)。这可能需要一些调整,因为对于 follow up 修订表来说,这是我的想法:

    ' additional array to hold the CBOs involved
    Private tgtCBOs As ComboBox()
    ...
    ' initialization:
    OptList.AddRange(New String() {"(None)", "Red", "Green", "Blue", "Violet", 
                           "Orange", "Mauve", "White"})
    tgtCBOs = New ComboBox() {cb1, cb2, cb3, cb4}
    
    ' set initial index to 0 with a default item
    
    Private Sub cb2_SelectedIndexChanged(sender As Object, e As EventArgs) Handles _ 
            cb2.SelectedIndexChanged, cb1.SelectedIndexChanged, cb3.SelectedIndexChanged
    
        If ignore Then Exit Sub
    
        Dim cbo = TryCast(sender, ComboBox)
        ' identify which one this is
        Dim ndx = Array.IndexOf(tgtCBOs, cbo)
        ' get all the selections from 0 to here
        Dim exclude = GetExclusionList(ndx)
        ' remove excludes from the NEXT cbo
        Dim newList As New List(Of String)
        If ndx + 1 < tgtCBOs.Length Then
            newList = OptList.Except(exclude).ToList()
            If newList(0) <> OptList(0) Then newList.Insert(0, "(None)")
            tgtCBOs(ndx + 1).DataSource = newList.ToArray()
        End If
    End Sub
    
    Private Function GetExclusionList(ndx As Int32) As List(Of String)
        Dim exclude As New List(Of String)
        For n As Int32 = 0 To ndx
            If tgtCBOs(n).SelectedIndex <> -1 Then
                exclude.Add(tgtCBOs(n).Items(tgtCBOs(n).SelectedIndex).ToString())
            End If
        Next
        Return exclude
    End Function
    

    请注意,最后一个 cbo 没有连接到该处理程序,因为它没有 "slave" 。如果您需要响应事件,请将其连接到自己的处理程序。

    此外,为“下一个”重置DataSource(或清除项目)的行为将导致该事件为下一个/子/从 CBO 触发。因此,对 CBO2 的更改将触发 3、4、5..n 的事件。它还会重置子/从/下一个中的先前选择。

    【讨论】:

    • 能否通过继续多个 if/else 语句将其扩展为 9 cbo?
    • 好的...第二个选项有效!只有一个小问题。我将如何保留第一个选项。假设我想包含一个始终可用的“无”选项。我看不到如何保留选项选择..
    • 就是这样……前几天我一直在寻找那个答案。我对 Q 或 A 的记忆不深,无法找到它
    • 由于它们是对象,您只能测试它们是否引用相同的对象。它们用途广泛,因此可以以多种方式使用,但通常我会比较价值。 If nvp1.Value &lt;&gt; nvp2.Value Then...。原因是像 {"Plutonium", 94} 这样的值通常是重要的部分,其名称是人类可读/可理解的版本。可能是其他情况(值==名称的某些索引}。该版本是非常基础的骨骼-您可以使用自定义比较器(应用程序到应用程序)来加强它,以使用“= / ”来比较任何部分( s)。
    • 是的,我的意思是 Equals 不是“= / ”,但编辑评论的宽限期已过。另见Implements IEquatable(Of NVP)
    【解决方案2】:

    好吧,假设您的组合框命名为 b1、b2 和 b3。所有这些组合都链接到相同的 SelectedIndexChanged 事件处理程序,并且(如您所说)您已将 b1、b2 和 b3 上的初始元素设置为固定的字符串列表。

    现在您还应该将 b2 和 b3 的 Enabled 属性设置为 false,并让 b1 上的选择在 SelectedIndexChanged 事件中驱动您的逻辑

    Sub onIndexChanged(sender As Object, e As EventArgs)
        Dim b As ComboBox = CType(sender, System.Windows.Forms.ComboBox)
        If b.Equals(b1) Then
            If b1.SelectedIndex = -1 Then
    
                b2.Enabled = False
                b3.Enabled = False
            Else
                b2.Enabled = True
                b3.Enabled = False
                b2.Items.Clear()
                b3.Items.Clear()
                b2.Items.AddRange(b1.Items.Cast(Of String)() _
                 .Where(Function(x) x <> b1.SelectedItem.ToString()).ToArray())
            End If
        Else if b.Equals(b2) Then
            If b2.SelectedIndex <> -1 Then
    
                b3.Items.Clear()
                b3.Items.AddRange(b2.Items.Cast(Of String)(). _
                    Where(Function(x) x <> b2.SelectedItem.ToString()).ToArray())
                b3.Enabled = True
                b3.SelectedIndex = 0
            End If 
        End If 
    End Sub
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-01-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多