ClearableComboBox für WinForms

    • VB.NET
    • .NET (FX) 4.5–4.8

    Es gibt 7 Antworten in diesem Thema. Der letzte Beitrag () ist von DerSmurf.

      ClearableComboBox für WinForms

      DataBinding ist eine tolle Sache. Auch die ComboBox ist sehr mächtig. Aber eines stört mich schon seit Längerem: Sobald man die ComboBox an ne gefüllte Datenquelle anschließt, kann man eine Selektion nicht mehr verhindern. Denn manchmal ergibt es eben doch Sinn, eben nichts ausgewählt zu haben. Und sei es nur, um dem User klarzumachen, dass er da vielleicht was vergessen hat. Daher hab ich mir ein UserControl zusammengebastelt, welches ich ClearableComboBox (CCB) nenne.
      Das Teil besteht aus einer ComboBox und einem Löschbutton. Für den WinForms-Designer gibt es für's DataBinding einen Designer-Editor via SmartTag.
      Erstmal das Teil in Aktion, dann der Quellcode.



      der Code zum gezeigten Programm

      VB.NET-Quellcode

      1. Public Class Form1
      2. Public Class TvChannel
      3. Property Name As String
      4. Property ListPosition As Integer
      5. End Class
      6. Public ReadOnly TvChannelList As New List(Of TvChannel)
      7. Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
      8. BsTvChannels.DataSource = TvChannelList
      9. BsTvChannels.Add(New TvChannel With {.Name = "ARD", .ListPosition = 1})
      10. BsTvChannels.Add(New TvChannel With {.Name = "ZDF", .ListPosition = 2})
      11. BsTvChannels.Add(New TvChannel With {.Name = "NDR", .ListPosition = 3})
      12. BsTvChannels.Add(New TvChannel With {.Name = "WDR", .ListPosition = 4})
      13. End Sub
      14. Private Sub BtnSwitchTvChannel_Click(sender As Object, e As EventArgs) Handles BtnSwitchTvChannel.Click
      15. If ClearableComboBox1.IsEmpty Then MessageBox.Show("Der Fernseher ist wohl aus :-(") : Return
      16. MessageBox.Show($"Sie schauen nun {DirectCast(ClearableComboBox1.SelectedItem, TvChannel).Name}.")
      17. End Sub
      18. End Class

      Ich habe die CCB über eine BindingSource an die TvChannelList gebunden



      und im Designer einen DefaultText für die CCB hinterlegt



      Nach Programmstart sieht man erstmal nur diesen Text. Klickt man auf den Button [Sender wechseln] (der nicht Teil der CCB ist ;) ), wird die Property IsEmpty ausgewertet, die jetzt erstmal True zurückgibt. Sobald man die Liste aber aufklappt, werden die Items der angebundenen Liste gezeigt und der DefaultText verschwindet. Klickt man danach auf [Sender wechseln], wird dieser mittels passendem Cast angezeigt. Und warum heißt das Ganze "Clearable" ComboBox? Dafür gibt es den Button [X], der die Auswahl wieder löscht.

      Wo wäre sowas u.a. sinnvoll: Wenn eine ComboBox eine Mitarbeiterliste anzeigt, bei der man festlegt, wer gerade eine Sache bearbeitet. Mit einer normalen ComboBox ist der erste Mitarbeiter immer gewählt und es wird ggf. vergessen diesen zu ändern. Und dann taucht er immer in der Protokollierung auf und ärgert sich, dass sein Name an erster Stelle in der Liste steht. Einen Dummy-Eintrag kann man auch nicht immer verwenden. Nun ja. Dies ist jedenfalls meine Lösung zu diesem Problem.

      Ach ja, der Code. Er teilt sich in 4 Dateien auf, wobei 2 nur für den DataBinding-Designer sind:
      Hauptdatei

      VB.NET-Quellcode

      1. <Designer(GetType(ClearableComboBoxDesigner))>
      2. <LookupBindingProperties(NameOf(ClearableComboBox.DataSource), NameOf(ClearableComboBox.DisplayMember), NameOf(ClearableComboBox.ValueMember), NameOf(ClearableComboBox.SelectedItem))>
      3. Public Class ClearableComboBox
      4. Public Property DataSource As Object = Nothing
      5. Public Property DisplayMember As String = Nothing
      6. Public Property ValueMember As String = Nothing
      7. Public Property DefaultText As String = Nothing
      8. Private _IsEmpty As Boolean = True
      9. Public Property IsEmpty As Boolean
      10. Get
      11. Return _IsEmpty
      12. End Get
      13. Private Set
      14. _IsEmpty = Value
      15. End Set
      16. End Property
      17. Public Property SelectedItem As Object
      18. Get
      19. Return CbxData.SelectedItem
      20. End Get
      21. Set
      22. If IsEmpty Then Return
      23. CbxData.SelectedItem = Value
      24. End Set
      25. End Property
      26. Private Sub BtnClearList_Click(sender As Object, e As EventArgs) Handles BtnClearList.Click
      27. ClearComboBox()
      28. End Sub
      29. Private Sub CbxData_DropDown(sender As Object, e As EventArgs) Handles CbxData.DropDown
      30. If DataSource Is Nothing Then Return
      31. CbxData.DataSource = DataSource
      32. CbxData.ValueMember = ValueMember
      33. CbxData.DisplayMember = DisplayMember
      34. IsEmpty = False
      35. End Sub
      36. Private Sub ClearableComboBox_Load(sender As Object, e As EventArgs) Handles Me.Load
      37. ClearComboBox()
      38. End Sub
      39. Private Sub ClearComboBox()
      40. CbxData.DataSource = Nothing
      41. CbxData.Items.Clear()
      42. Dim DefaultItem = ""
      43. If DefaultText.IsNotEmpty Then DefaultItem = DefaultText
      44. CbxData.Items.Add(DefaultItem)
      45. CbxData.SelectedIndex = 0
      46. _IsEmpty = True
      47. End Sub
      48. End Class

      Designer.VB

      VB.NET-Quellcode

      1. <Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()> _
      2. Partial Class ClearableComboBox
      3. Inherits System.Windows.Forms.UserControl
      4. 'UserControl überschreibt den Löschvorgang, um die Komponentenliste zu bereinigen.
      5. <System.Diagnostics.DebuggerNonUserCode()> _
      6. Protected Overrides Sub Dispose(ByVal disposing As Boolean)
      7. Try
      8. If disposing AndAlso components IsNot Nothing Then
      9. components.Dispose()
      10. End If
      11. Finally
      12. MyBase.Dispose(disposing)
      13. End Try
      14. End Sub
      15. 'Wird vom Windows Form-Designer benötigt.
      16. Private components As System.ComponentModel.IContainer
      17. 'Hinweis: Die folgende Prozedur ist für den Windows Form-Designer erforderlich.
      18. 'Das Bearbeiten ist mit dem Windows Form-Designer möglich.
      19. 'Das Bearbeiten mit dem Code-Editor ist nicht möglich.
      20. <System.Diagnostics.DebuggerStepThrough()> _
      21. Private Sub InitializeComponent()
      22. Me.BtnClearList = New System.Windows.Forms.Button()
      23. Me.CbxData = New System.Windows.Forms.ComboBox()
      24. Me.SuspendLayout()
      25. '
      26. 'BtnClearList
      27. '
      28. Me.BtnClearList.Anchor = CType((System.Windows.Forms.AnchorStyles.Top Or System.Windows.Forms.AnchorStyles.Right), System.Windows.Forms.AnchorStyles)
      29. Me.BtnClearList.Location = New System.Drawing.Point(126, 3)
      30. Me.BtnClearList.Name = "BtnClearList"
      31. Me.BtnClearList.Size = New System.Drawing.Size(21, 21)
      32. Me.BtnClearList.TabIndex = 3
      33. Me.BtnClearList.Text = "X"
      34. Me.BtnClearList.UseVisualStyleBackColor = True
      35. '
      36. 'CbxData
      37. '
      38. Me.CbxData.Anchor = CType(((System.Windows.Forms.AnchorStyles.Top Or System.Windows.Forms.AnchorStyles.Left) _
      39. Or System.Windows.Forms.AnchorStyles.Right), System.Windows.Forms.AnchorStyles)
      40. Me.CbxData.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList
      41. Me.CbxData.FormattingEnabled = True
      42. Me.CbxData.Location = New System.Drawing.Point(3, 3)
      43. Me.CbxData.Name = "CbxData"
      44. Me.CbxData.Size = New System.Drawing.Size(117, 21)
      45. Me.CbxData.TabIndex = 2
      46. '
      47. 'ClearableComboBox
      48. '
      49. Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!)
      50. Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
      51. Me.Controls.Add(Me.BtnClearList)
      52. Me.Controls.Add(Me.CbxData)
      53. Me.Name = "ClearableComboBox"
      54. Me.Size = New System.Drawing.Size(147, 27)
      55. Me.ResumeLayout(False)
      56. End Sub
      57. Private WithEvents BtnClearList As Button
      58. Private WithEvents CbxData As ComboBox
      59. End Class


      Zusatzdatei1

      VB.NET-Quellcode

      1. Imports System.ComponentModel.Design
      2. Public Class ClearableComboBoxActionList : Inherits DesignerActionList
      3. Private ReadOnly ClearableComboBox As ClearableComboBox = Nothing
      4. Private ReadOnly DesignerActionUIService As DesignerActionUIService = Nothing
      5. Public Sub New(Component As IComponent)
      6. MyBase.New(Component)
      7. ClearableComboBox = DirectCast(Component, ClearableComboBox)
      8. DesignerActionUIService = DirectCast(GetService(GetType(DesignerActionUIService)), DesignerActionUIService)
      9. End Sub
      10. Private Function GetPropertyByName(Name As String) As PropertyDescriptor
      11. Dim FittingProperty = TypeDescriptor.GetProperties(ClearableComboBox)(Name)
      12. If FittingProperty.NotExists Then Throw New ArgumentException("Matching property not found!", Name)
      13. Return FittingProperty
      14. End Function
      15. <AttributeProvider(GetType(IListSource))>
      16. Public Property DataSource() As Object
      17. Get
      18. Return ClearableComboBox.DataSource
      19. End Get
      20. Set
      21. GetPropertyByName(NameOf(DataSource)).SetValue(ClearableComboBox, Value)
      22. End Set
      23. End Property
      24. <DefaultValue("")> <Editor("System.Windows.Forms.Design.DataMemberFieldEditor", GetType(Design.UITypeEditor))>
      25. Public Property DisplayMember() As String
      26. Get
      27. Return ClearableComboBox.DisplayMember
      28. End Get
      29. Set
      30. GetPropertyByName(NameOf(DisplayMember)).SetValue(ClearableComboBox, Value)
      31. End Set
      32. End Property
      33. <DefaultValue(""), Editor("System.Windows.Forms.Design.DataMemberFieldEditor", GetType(Design.UITypeEditor))>
      34. Public Property ValueMember() As String
      35. Get
      36. Return ClearableComboBox.ValueMember
      37. End Get
      38. Set
      39. GetPropertyByName(NameOf(ValueMember)).SetValue(ClearableComboBox, Value)
      40. End Set
      41. End Property
      42. Public Overrides Function GetSortedActionItems() As DesignerActionItemCollection
      43. Dim SmartTagItems As New DesignerActionItemCollection From {New DesignerActionHeaderItem("Daten"),
      44. New DesignerActionPropertyItem(NameOf(DataSource), "Datenquelle", "Data", "legt die Datenquelle fest"),
      45. New DesignerActionPropertyItem(NameOf(DisplayMember), "Anzeigemember", "Data", "legt den Anzeigewert fest"),
      46. New DesignerActionPropertyItem(NameOf(ValueMember), "Wertemember", "Data", "legt den Wertewert fest")}
      47. Return SmartTagItems
      48. End Function
      49. End Class

      Zusatzdatei2

      VB.NET-Quellcode

      1. Imports System.ComponentModel.Design
      2. <Security.Permissions.PermissionSet(Security.Permissions.SecurityAction.Demand, Name:="FullTrust")>
      3. Public Class ClearableComboBoxDesigner : Inherits Windows.Forms.Design.ControlDesigner
      4. Private ActionList As DesignerActionListCollection = Nothing
      5. Public Overrides ReadOnly Property ActionLists() As DesignerActionListCollection
      6. Get
      7. If ActionList.NotExists Then ActionList = New DesignerActionListCollection From {New ClearableComboBoxActionList(Component)}
      8. Return ActionList
      9. End Get
      10. End Property
      11. End Class
      Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

      Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
      Nachdem ich festgestellt habe, dass es u.a. bei Schriftgrößenveränderungen Probleme gibt und das Fehlen des SelectedItems mich doch etwas wurmt, habe ich die freien Tage genutzt, um etwas nachzubessern.
      Das Teil ist jetzt nur noch eine spezialisierte ComboBox, die auf Befehl das Deselektionsverhalten aufweist.
      Spoiler anzeigen

      VB.NET-Quellcode

      1. Public Class ClearableComboBox : Inherits ComboBox
      2. Public Property DefaultText As String = Nothing
      3. Private _IsEmpty As Boolean = True
      4. Private _DataSource As Object
      5. Private _ValueMember As String
      6. Private _DisplayMember As String
      7. Private _DataBindingToRemember As Binding = Nothing
      8. Public Property IsEmpty As Boolean
      9. Get
      10. Return _IsEmpty
      11. End Get
      12. Private Set
      13. _IsEmpty = Value
      14. End Set
      15. End Property
      16. Public Sub New()
      17. MyBase.New
      18. ResetDropDownStyle()
      19. End Sub
      20. Private Sub ResetDropDownStyle()
      21. DropDownStyle = ComboBoxStyle.DropDownList
      22. End Sub
      23. Private Sub ClearableComboBox_DropDownStyleChanged(sender As Object, e As EventArgs) Handles Me.DropDownStyleChanged
      24. ResetDropDownStyle()
      25. End Sub
      26. Public Sub Clear()
      27. SaveCurrentData()
      28. RemoveControlData()
      29. SetDefaultTextAsOnlyItem()
      30. TreatMeAsEmpty()
      31. End Sub
      32. Private Sub SaveCurrentData()
      33. If DataSource Is Nothing Then Return
      34. _DataSource = DataSource
      35. _ValueMember = ValueMember
      36. _DisplayMember = DisplayMember
      37. If DataBindings.Count > 0 Then _DataBindingToRemember = DataBindings(0)
      38. End Sub
      39. Private Sub RemoveControlData()
      40. DataSource = Nothing
      41. If DataBindings.Count > 0 Then DataBindings.RemoveAt(0)
      42. End Sub
      43. Private Sub SetDefaultTextAsOnlyItem()
      44. Items.Clear()
      45. Items.Add(If(String.IsNullOrEmpty(DefaultText), "", DefaultText))
      46. SelectedIndex = 0
      47. End Sub
      48. Private Sub TreatMeAsEmpty()
      49. _IsEmpty = True
      50. End Sub
      51. Private Sub ClearableComboBox_DropDown(sender As Object, e As EventArgs) Handles Me.DropDown
      52. If _DataSource Is Nothing Then Return
      53. RestoreData()
      54. TreatMeAsFilled()
      55. End Sub
      56. Private Sub RestoreData()
      57. DataSource = _DataSource
      58. ValueMember = _ValueMember
      59. DisplayMember = _DisplayMember
      60. If DataBindings.Count = 0 AndAlso _DataBindingToRemember IsNot Nothing Then DataBindings.Add(_DataBindingToRemember)
      61. End Sub
      62. Private Sub TreatMeAsFilled()
      63. IsEmpty = False
      64. End Sub
      65. End Class


      Anbei ein kleines Testprojekt.
      Im ersten Tab-Reiter kann man eine Firma aussuchen und »kontaktieren« (es erscheint natürlich nur eine MessageBox), sofern eine Auswahl getroffen wurde.
      Im zweiten Tab-Reiter kann man ein Fahrzeug mit einer Firma verknüpfen, sofern eine Auswahl getroffen wurde. Dies zeigt die normale Funktionalität der bisher fehlenden Eigenschaft »ausgewählter Wert«
      Dateien
      Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

      Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
      Ein kleines Code-Update, weil mir immer wieder doch ein paar Kleinigkeiten aufgefallen sind.
      Wenn man im Designer ein DataBinding eingebaut hatte und das Projekt neulud, wurde es vermeintlich wieder entfernt, was zu Verwirrung führte. Es war zwar zwischengespeichert, aber die Anzeige im Designer machte das nicht klar.
      Auch das Setzen des DefaultTextes führte zu diesem Effekt.
      Diese Verhaltensweisen sind nun entfernt. Dementsprechend bleibt es dem Programmierer überlassen, ob er bei Programmstart die CCB-Auswahl löscht (also CCB.Clear ausführt und somit den DefaultText anzeigen lässt) oder nicht. Wär natürlich m.E. immer sinnvoll, da man ja zu Beginn eben keine Auswahl getroffen haben will.
      Der DropDownStyle ist nun versteckt und wenn trotzdem jemand versucht, den Style zu ändern, läuft das ins Leere :rolleyes:
      Spoiler anzeigen

      VB.NET-Quellcode

      1. Imports System.ComponentModel
      2. <ToolboxItem(True),
      3. Description("eine DropDownList-ComboBox, deren DataBinding-Auswahl auch gelöscht werden kann")>
      4. Public Class ClearableComboBox : Inherits ComboBox
      5. '''<summary>der anzuzeigende Text bei Nicht-Auswahl</summary>
      6. Property DefaultText As String = "(keine Auswahl getroffen)"
      7. <Browsable(False)> Shadows Property DropDownStyle As ComboBoxStyle
      8. Get
      9. Return MyBase.DropDownStyle
      10. End Get
      11. Set
      12. MyBase.DropDownStyle = ComboBoxStyle.DropDownList
      13. End Set
      14. End Property
      15. '''<summary>gibt wieder, ob keine Auswahl getroffen wurde</summary>
      16. Private _IsEmpty As Boolean = True
      17. Public Property IsEmpty As Boolean
      18. Get
      19. Return _IsEmpty
      20. End Get
      21. Private Set
      22. _IsEmpty = Value
      23. End Set
      24. End Property
      25. Private _DataSource As Object
      26. Private _ValueMember As String
      27. Private _DisplayMember As String
      28. Private _DataBindingToRemember As Binding = Nothing
      29. Public Sub New()
      30. MyBase.New
      31. DropDownStyle = ComboBoxStyle.DropDownList
      32. End Sub
      33. '''<summary>löscht die eventuell bereits getätigte Auswahl</summary>
      34. Public Sub Clear()
      35. SaveCurrentData()
      36. RemoveControlData()
      37. SetDefaultTextAsOnlyItem()
      38. TreatMeAsEmpty()
      39. End Sub
      40. Private Sub SaveCurrentData()
      41. If DataSource Is Nothing Then Return
      42. _DataSource = DataSource
      43. _ValueMember = ValueMember
      44. _DisplayMember = DisplayMember
      45. If DataBindings.Count > 0 Then _DataBindingToRemember = DataBindings(0)
      46. End Sub
      47. Private Sub RemoveControlData()
      48. DataSource = Nothing
      49. If DataBindings.Count > 0 Then DataBindings.RemoveAt(0)
      50. End Sub
      51. Private Sub SetDefaultTextAsOnlyItem()
      52. Items.Clear()
      53. If String.IsNullOrEmpty(DefaultText) Then Return
      54. Items.Add(DefaultText)
      55. SelectedIndex = 0
      56. End Sub
      57. Private Sub TreatMeAsEmpty()
      58. _IsEmpty = True
      59. End Sub
      60. Private Sub ClearableComboBox_DropDown(sender As Object, e As EventArgs) Handles Me.DropDown
      61. If _DataSource Is Nothing Then Return
      62. RestoreData()
      63. TreatMeAsFilled()
      64. End Sub
      65. Private Sub RestoreData()
      66. DataSource = _DataSource
      67. ValueMember = _ValueMember
      68. DisplayMember = _DisplayMember
      69. If DataBindings.Count = 0 AndAlso _DataBindingToRemember IsNot Nothing Then DataBindings.Add(_DataBindingToRemember)
      70. End Sub
      71. Private Sub TreatMeAsFilled()
      72. IsEmpty = False
      73. End Sub
      74. End Class

      Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

      Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
      Huhu. Ich habe eine Frage (oder einen Verbesserungsvorschlag?) zu deiner CCB, die ich an mehreren Stellen nutze. Teilweise nutze ich auch die "normale" CB.
      Bei der normal ComboBox kann ich die ​AutoCompleteSource auf ListItems, den ​AutoCompleteMode auf Append und DropDownStyle auf DropDownList stellen.
      Dadurch wird erreicht, dass innerhalb der ComboBox nur Einträge der angestöpselten Liste ausgewählt werden können, es ist aber möglich mit reiner Tastatureingabe einen Eintrag auszuwählen.
      Gibt es also z.B. die 3 Einträge "Coca Cola", "Coalabär", und "CoCoCo", kann ich die CB auswählen und "coa" eingeben, um Coalabär auszuwählen.

      In der CCB ist dies so nicht möglich, da sämtliche Einstellungen (außer None) im ​AutoCompleteMode zum folgendem Fehler führen:
      ​System.NotSupportedException: "Nur der Wert AutoCompleteMode.None kann verwendet werden, wenn für DropDownStyle die Einstellung ComboBoxStyle.DropDownList und für AutoCompleteSource nicht die Einstellung AutoCompleteSource.ListItems gilt."

      Es ist hier also nur möglich, die vorhandenen Einträge nach dem Anfangsbustaben vorzusortieren.
      Das ist tatsächlich (bisher) absichtlich so. Man soll nur aus vorhandenen Einträgen wählen dürfen. Würde man selber eintippen können, könnten auch datenquellenfremde Eingaben gemacht werden. Das Ganze ist ja open source, daher kannst Du da natürlich Anpassungen vornehmen, falls gebraucht.
      Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

      Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.

      VaporiZed schrieb:

      Man soll nur aus vorhandenen Einträgen wählen dürfen

      Wenn aber der DropDownStyle auf DropDownList steht, was ja bei der CCB im Designer auf nicht änderbar ist, können ja generell nur vorhandene Einträge ausgewählt werden, auch wenn mit Append und dergleichen gearbeitet wird.
      Jetzt habe ich es verstanden. Eine Zeile im Konstruktor sorgt für das »Problem«: Entferne die Zeile DropDownStyle = ComboBoxStyle.DropDownList, dann kannst Du AutoCompleteMode = System.Windows.Forms.AutoCompleteMode.Append und AutoCompleteSource = System.Windows.Forms.AutoCompleteSource.ListItems setzen.
      Allerdings musst Du dann selbst zu Programmstart oder besser in der FormX.Designer.VB DropDownStyle = ComboBoxStyle.DropDownList setzen. Ansonsten hast Du ein normales ComboBox-Verhalten, was sich dann … irgendwie verhält. Ich sag nur Freitext.
      Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

      Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
      Vielen Dank, genau das habe ich gemeint. Nun kann ich mit der Tastatur einfach in die CCB schreiben (und eben nach mehr suchen, als nur dem Anfangsbuchstaben) und trotzdem nur Werte auswählen, die in der Liste vorhanden sind.