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
Ich habe die CCB über eine BindingSource an die
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
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
Designer.VB
Zusatzdatei1
Zusatzdatei2
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.
VB.NET-Quellcode
- Public Class Form1
- Public Class TvChannel
- Property Name As String
- Property ListPosition As Integer
- End Class
- Public ReadOnly TvChannelList As New List(Of TvChannel)
- Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
- BsTvChannels.DataSource = TvChannelList
- BsTvChannels.Add(New TvChannel With {.Name = "ARD", .ListPosition = 1})
- BsTvChannels.Add(New TvChannel With {.Name = "ZDF", .ListPosition = 2})
- BsTvChannels.Add(New TvChannel With {.Name = "NDR", .ListPosition = 3})
- BsTvChannels.Add(New TvChannel With {.Name = "WDR", .ListPosition = 4})
- End Sub
- Private Sub BtnSwitchTvChannel_Click(sender As Object, e As EventArgs) Handles BtnSwitchTvChannel.Click
- If ClearableComboBox1.IsEmpty Then MessageBox.Show("Der Fernseher ist wohl aus :-(") : Return
- MessageBox.Show($"Sie schauen nun {DirectCast(ClearableComboBox1.SelectedItem, TvChannel).Name}.")
- End Sub
- End Class
Ich habe die CCB über eine BindingSource an die
TvChannelList
gebundenund 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:
VB.NET-Quellcode
- <Designer(GetType(ClearableComboBoxDesigner))>
- <LookupBindingProperties(NameOf(ClearableComboBox.DataSource), NameOf(ClearableComboBox.DisplayMember), NameOf(ClearableComboBox.ValueMember), NameOf(ClearableComboBox.SelectedItem))>
- Public Class ClearableComboBox
- Public Property DataSource As Object = Nothing
- Public Property DisplayMember As String = Nothing
- Public Property ValueMember As String = Nothing
- Public Property DefaultText As String = Nothing
- Private _IsEmpty As Boolean = True
- Public Property IsEmpty As Boolean
- Get
- Return _IsEmpty
- End Get
- Private Set
- _IsEmpty = Value
- End Set
- End Property
- Public Property SelectedItem As Object
- Get
- Return CbxData.SelectedItem
- End Get
- Set
- If IsEmpty Then Return
- CbxData.SelectedItem = Value
- End Set
- End Property
- Private Sub BtnClearList_Click(sender As Object, e As EventArgs) Handles BtnClearList.Click
- ClearComboBox()
- End Sub
- Private Sub CbxData_DropDown(sender As Object, e As EventArgs) Handles CbxData.DropDown
- If DataSource Is Nothing Then Return
- CbxData.DataSource = DataSource
- CbxData.ValueMember = ValueMember
- CbxData.DisplayMember = DisplayMember
- IsEmpty = False
- End Sub
- Private Sub ClearableComboBox_Load(sender As Object, e As EventArgs) Handles Me.Load
- ClearComboBox()
- End Sub
- Private Sub ClearComboBox()
- CbxData.DataSource = Nothing
- CbxData.Items.Clear()
- Dim DefaultItem = ""
- If DefaultText.IsNotEmpty Then DefaultItem = DefaultText
- CbxData.Items.Add(DefaultItem)
- CbxData.SelectedIndex = 0
- _IsEmpty = True
- End Sub
- End Class
VB.NET-Quellcode
- <Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()> _
- Partial Class ClearableComboBox
- Inherits System.Windows.Forms.UserControl
- 'UserControl überschreibt den Löschvorgang, um die Komponentenliste zu bereinigen.
- <System.Diagnostics.DebuggerNonUserCode()> _
- Protected Overrides Sub Dispose(ByVal disposing As Boolean)
- Try
- If disposing AndAlso components IsNot Nothing Then
- components.Dispose()
- End If
- Finally
- MyBase.Dispose(disposing)
- End Try
- End Sub
- 'Wird vom Windows Form-Designer benötigt.
- Private components As System.ComponentModel.IContainer
- 'Hinweis: Die folgende Prozedur ist für den Windows Form-Designer erforderlich.
- 'Das Bearbeiten ist mit dem Windows Form-Designer möglich.
- 'Das Bearbeiten mit dem Code-Editor ist nicht möglich.
- <System.Diagnostics.DebuggerStepThrough()> _
- Private Sub InitializeComponent()
- Me.BtnClearList = New System.Windows.Forms.Button()
- Me.CbxData = New System.Windows.Forms.ComboBox()
- Me.SuspendLayout()
- '
- 'BtnClearList
- '
- Me.BtnClearList.Anchor = CType((System.Windows.Forms.AnchorStyles.Top Or System.Windows.Forms.AnchorStyles.Right), System.Windows.Forms.AnchorStyles)
- Me.BtnClearList.Location = New System.Drawing.Point(126, 3)
- Me.BtnClearList.Name = "BtnClearList"
- Me.BtnClearList.Size = New System.Drawing.Size(21, 21)
- Me.BtnClearList.TabIndex = 3
- Me.BtnClearList.Text = "X"
- Me.BtnClearList.UseVisualStyleBackColor = True
- '
- 'CbxData
- '
- Me.CbxData.Anchor = CType(((System.Windows.Forms.AnchorStyles.Top Or System.Windows.Forms.AnchorStyles.Left) _
- Or System.Windows.Forms.AnchorStyles.Right), System.Windows.Forms.AnchorStyles)
- Me.CbxData.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList
- Me.CbxData.FormattingEnabled = True
- Me.CbxData.Location = New System.Drawing.Point(3, 3)
- Me.CbxData.Name = "CbxData"
- Me.CbxData.Size = New System.Drawing.Size(117, 21)
- Me.CbxData.TabIndex = 2
- '
- 'ClearableComboBox
- '
- Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!)
- Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
- Me.Controls.Add(Me.BtnClearList)
- Me.Controls.Add(Me.CbxData)
- Me.Name = "ClearableComboBox"
- Me.Size = New System.Drawing.Size(147, 27)
- Me.ResumeLayout(False)
- End Sub
- Private WithEvents BtnClearList As Button
- Private WithEvents CbxData As ComboBox
- End Class
VB.NET-Quellcode
- Imports System.ComponentModel.Design
- Public Class ClearableComboBoxActionList : Inherits DesignerActionList
- Private ReadOnly ClearableComboBox As ClearableComboBox = Nothing
- Private ReadOnly DesignerActionUIService As DesignerActionUIService = Nothing
- Public Sub New(Component As IComponent)
- MyBase.New(Component)
- ClearableComboBox = DirectCast(Component, ClearableComboBox)
- DesignerActionUIService = DirectCast(GetService(GetType(DesignerActionUIService)), DesignerActionUIService)
- End Sub
- Private Function GetPropertyByName(Name As String) As PropertyDescriptor
- Dim FittingProperty = TypeDescriptor.GetProperties(ClearableComboBox)(Name)
- If FittingProperty.NotExists Then Throw New ArgumentException("Matching property not found!", Name)
- Return FittingProperty
- End Function
- <AttributeProvider(GetType(IListSource))>
- Public Property DataSource() As Object
- Get
- Return ClearableComboBox.DataSource
- End Get
- Set
- GetPropertyByName(NameOf(DataSource)).SetValue(ClearableComboBox, Value)
- End Set
- End Property
- <DefaultValue("")> <Editor("System.Windows.Forms.Design.DataMemberFieldEditor", GetType(Design.UITypeEditor))>
- Public Property DisplayMember() As String
- Get
- Return ClearableComboBox.DisplayMember
- End Get
- Set
- GetPropertyByName(NameOf(DisplayMember)).SetValue(ClearableComboBox, Value)
- End Set
- End Property
- <DefaultValue(""), Editor("System.Windows.Forms.Design.DataMemberFieldEditor", GetType(Design.UITypeEditor))>
- Public Property ValueMember() As String
- Get
- Return ClearableComboBox.ValueMember
- End Get
- Set
- GetPropertyByName(NameOf(ValueMember)).SetValue(ClearableComboBox, Value)
- End Set
- End Property
- Public Overrides Function GetSortedActionItems() As DesignerActionItemCollection
- Dim SmartTagItems As New DesignerActionItemCollection From {New DesignerActionHeaderItem("Daten"),
- New DesignerActionPropertyItem(NameOf(DataSource), "Datenquelle", "Data", "legt die Datenquelle fest"),
- New DesignerActionPropertyItem(NameOf(DisplayMember), "Anzeigemember", "Data", "legt den Anzeigewert fest"),
- New DesignerActionPropertyItem(NameOf(ValueMember), "Wertemember", "Data", "legt den Wertewert fest")}
- Return SmartTagItems
- End Function
- End Class
VB.NET-Quellcode
- Imports System.ComponentModel.Design
- <Security.Permissions.PermissionSet(Security.Permissions.SecurityAction.Demand, Name:="FullTrust")>
- Public Class ClearableComboBoxDesigner : Inherits Windows.Forms.Design.ControlDesigner
- Private ActionList As DesignerActionListCollection = Nothing
- Public Overrides ReadOnly Property ActionLists() As DesignerActionListCollection
- Get
- If ActionList.NotExists Then ActionList = New DesignerActionListCollection From {New ClearableComboBoxActionList(Component)}
- Return ActionList
- End Get
- End Property
- 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.
Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.