Die Auswahlliste in einer DataGridViewComboBox ändern (die Zweite)

  • VB.NET

Es gibt 4 Antworten in diesem Thema. Der letzte Beitrag () ist von VB1963.

    Die Auswahlliste in einer DataGridViewComboBox ändern (die Zweite)

    Hallo Community!

    Ich habe meinen geschlossenen Beitrag Nach erfolgter Auswahl die Auswahlliste in einer DataGridViewComboBox ändern wieder 'aufgemacht'. :)
    Mich hat dieses damalige Vorhaben wieder aus Interesse und Neugier gepackt und habe versucht weiterzumachen.
    Der Beitrag Items Collection Property erstellen von Demmy hat mich zu neuen Ideen verleitet.

    Mein damaliges Problem:
    Eine ComboBox in einer DataGridView anzuwenden, die ihre Listeneinträge um den jeweils ausgewählten Eintrag reduziert,
    damit nur ein Wert der Auswahlliste in einer Spalte vorkommen kann.
    Ich hatte es damals mit einer ComboBoxColumn versucht und damit nur DGV-Ausnahmen,
    wie "Der DataGridViewComboBoxCell-Wert ist ungültig" produziert. :whistling:
    Des Weiteren konnte ich nur eine Spalte im DGV bedienen und hatte auch keine richtige Datenanbindung...

    Spoiler anzeigen

    VB.NET-Quellcode

    1. Imports System
    2. Imports System.ComponentModel
    3. Imports System.Drawing.Design
    4. <Localizable(True)> _
    5. Public Class DepressComboBoxListColumn : Inherits DataGridViewColumn
    6. Private _DataSource As Object
    7. Private _ValueMember As String
    8. Private _DisplayMember As String
    9. Private _Items As New List(Of String)
    10. Public Sub New()
    11. MyBase.New(New DepressComboBoxListCell())
    12. End Sub
    13. ''' <summary>
    14. ''' Mit der Clone-Methode wird erreicht,
    15. ''' dass schlussendlich der Form-Desiner
    16. ''' die Daten vom Eigenschaftsfenster übernimmt!!!
    17. ''' </summary>
    18. ''' <returns></returns>
    19. ''' <remarks></remarks>
    20. Public Overrides Function Clone() As Object
    21. Dim col As DepressComboBoxListColumn = DirectCast(MyBase.Clone(), DepressComboBoxListColumn)
    22. col.CellTemplate = DirectCast(Me.CellTemplate.Clone(), DepressComboBoxListCell)
    23. col.Items = Me.Items
    24. col.DataSource = Me.DataSource
    25. col.DisplayMember = Me.DisplayMember
    26. col.ValueMember = Me.ValueMember
    27. col.DropDownStyle = Me.DropDownStyle
    28. col.FlatStyle = Me.FlatStyle
    29. Return col
    30. End Function
    31. <Browsable(False)> _
    32. <DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)> _
    33. Public Overrides Property CellTemplate() As DataGridViewCell
    34. Get
    35. Return MyBase.CellTemplate
    36. End Get
    37. Set(value As DataGridViewCell)
    38. If (value IsNot Nothing) AndAlso Not (TypeOf value Is DepressComboBoxListCell) Then
    39. Throw New ArgumentException("DataGridView: falscher Typ von CellTemplate, es muss eine DepressComboBoxListCell sein")
    40. End If
    41. MyBase.CellTemplate = value
    42. End Set
    43. End Property
    44. #Region "ComboBoxStyle"
    45. Private _DropDownStyle As ComboBoxStyle
    46. <Category("Darstellung")> _
    47. <Description("Steuert die Darstellung und Funktionalität der Combobox.")> _
    48. <ReadOnlyAttribute(False)> _
    49. <DefaultValue(ComboBoxStyle.DropDown)> _
    50. <DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)> _
    51. <RefreshProperties(RefreshProperties.Repaint)> _
    52. Public Property DropDownStyle() As ComboBoxStyle
    53. Get
    54. If _DropDownStyle = ComboBoxStyle.Simple Then _DropDownStyle = ComboBoxStyle.DropDown
    55. Return _DropDownStyle
    56. End Get
    57. Set(value As ComboBoxStyle)
    58. _DropDownStyle = value
    59. End Set
    60. End Property
    61. Private _FlatStyle As FlatStyle
    62. <Category("Darstellung")> _
    63. <Description("Bestimmt die Anzeige der Combobox.")> _
    64. <ReadOnlyAttribute(False)> _
    65. <DefaultValue(FlatStyle.Standard)> _
    66. <DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)> _
    67. <RefreshProperties(RefreshProperties.Repaint)> _
    68. Public Property FlatStyle() As FlatStyle
    69. Get
    70. Return _FlatStyle
    71. End Get
    72. Set(value As FlatStyle)
    73. _FlatStyle = value
    74. End Set
    75. End Property
    76. #End Region
    77. #Region "Datenherkunft"
    78. <Category("Data")> _
    79. <Description("Die Datenquelle, die die Auswahl für die Kombinationsfelder auffüllt.")> _
    80. <DefaultValue(DirectCast(Nothing, String))> _
    81. <DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)> _
    82. <RefreshProperties(RefreshProperties.All)> _
    83. <Localizable(False)> _
    84. <MergableProperty(False)> _
    85. <TypeConverter("System.Windows.Forms.Design.DataSourceConverter, " & _
    86. "System.Design, " & _
    87. "Version=4.0.0.0, " & _
    88. "Culture=neutral, " & _
    89. "PublicKeyToken=b03f5f7f11d50a3a")> _
    90. <AttributeProvider(GetType(IListSource))> _
    91. Public Property DataSource() As Object
    92. Get
    93. Return _DataSource
    94. End Get
    95. Set(value As Object)
    96. If value IsNot Nothing AndAlso Not (TypeOf value Is IList OrElse TypeOf value Is IListSource) Then
    97. Throw New Exception("Die angegebene DataSource ist für eine komplexe Datenbindung ungeeignet")
    98. Else
    99. If _DataSource IsNot value Then
    100. _DataSource = value
    101. Me.Items.Clear()
    102. If IsNothing(value) Then
    103. Me.ValueMember = String.Empty
    104. Me.DisplayMember = String.Empty
    105. End If
    106. End If
    107. End If
    108. End Set
    109. End Property
    110. <Category("Data")> _
    111. <Description("Eine Zeichenfolge, die die Eigenschaft oder Spalte angibt, " & _
    112. "von der Zeichenfolgen für die Anzeige in den Kombinationsfeldern abgerufen werden.")> _
    113. <DefaultValue(DirectCast(Nothing, String))> _
    114. <DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)> _
    115. <RefreshProperties(RefreshProperties.All)> _
    116. <Localizable(False)> _
    117. <MergableProperty(False)> _
    118. <TypeConverter("System.Windows.Forms.Design.DataMemberFieldConverter, " & _
    119. "System.Design, " & _
    120. "Version=4.0.0.0, " & _
    121. "Culture=neutral, " & _
    122. "PublicKeyToken=b03f5f7f11d50a3a")> _
    123. <Editor("System.Windows.Forms.Design.DataMemberFieldEditor, " & _
    124. "System.Design, " & _
    125. "Version=4.0.0.0, " & _
    126. "Culture=neutral, " & _
    127. "PublicKeyToken=b03f5f7f11d50a3a", _
    128. GetType(System.Drawing.Design.UITypeEditor))> _
    129. Public Property DisplayMember() As String
    130. Get
    131. Return _DisplayMember
    132. End Get
    133. Set(value As String)
    134. If _DisplayMember <> value Then _DisplayMember = value
    135. End Set
    136. End Property
    137. <Category("Data")> _
    138. <Description("Eine Zeichenfolge, die die Eigenschaft oder Spalte angibt, " & _
    139. "aus der Werte abgerufen werden, die der Auswahl in der Dropdownliste entsprechen.")> _
    140. <DefaultValue(DirectCast(Nothing, String))> _
    141. <DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)> _
    142. <RefreshProperties(RefreshProperties.All)> _
    143. <Localizable(False)> _
    144. <MergableProperty(False)> _
    145. <TypeConverter("System.Windows.Forms.Design.DataMemberFieldConverter, " & _
    146. "System.Design, " & _
    147. "Version=4.0.0.0, " & _
    148. "Culture=neutral, " & _
    149. "PublicKeyToken=b03f5f7f11d50a3a")> _
    150. <Editor("System.Windows.Forms.Design.DataMemberFieldEditor, " & _
    151. "System.Design, " & _
    152. "Version=4.0.0.0, " & _
    153. "Culture=neutral, " & _
    154. "PublicKeyToken=b03f5f7f11d50a3a", _
    155. GetType(System.Drawing.Design.UITypeEditor))> _
    156. Public Property ValueMember() As String
    157. Get
    158. Return _ValueMember
    159. End Get
    160. Set(value As String)
    161. If _ValueMember <> value Then _ValueMember = value
    162. End Set
    163. End Property
    164. <Category("Data")> _
    165. <Description("Eine Auflistung der Objekte, die in den Kombinationsfeldern " & _
    166. "als Auswahl verwendet werden.")> _
    167. <DesignerSerializationVisibility(DesignerSerializationVisibility.Content)> _
    168. <Localizable(False)> _
    169. <MergableProperty(False)> _
    170. <Editor("System.Windows.Forms.Design.ListControlStringCollectionEditor, " & _
    171. "System.Design, " & _
    172. "Version=4.0.0.0, " & _
    173. "Culture=neutral, " & _
    174. "PublicKeyToken=b03f5f7f11d50a3a",
    175. GetType(System.Drawing.Design.UITypeEditor))> _
    176. Public Property Items As List(Of String)
    177. Get
    178. Return _Items
    179. End Get
    180. Set(value As List(Of String))
    181. If IsNothing(Me.DataSource) Then _Items = value
    182. End Set
    183. End Property
    184. #End Region
    185. End Class 'DepressComboBoxListColumn
    186. Public Class DepressComboBoxListCell : Inherits DataGridViewTextBoxCell
    187. Public Sub New()
    188. Me.Style.Format = String.Empty
    189. End Sub
    190. Public Overrides Sub InitializeEditingControl(ByVal rowIndex As Integer, _
    191. ByVal initialFormattedValue As Object, _
    192. ByVal dataGridViewCellStyle As DataGridViewCellStyle)
    193. ' den Wert des Bearbeitungsteuerelementes auf den aktuellen Zellwert setzen.
    194. MyBase.InitializeEditingControl(rowIndex, initialFormattedValue, dataGridViewCellStyle)
    195. '
    196. Dim ctl As DepressComboBoxListEditingControl =
    197. CType(Me.DataGridView.EditingControl, DepressComboBoxListEditingControl)
    198. If Not String.IsNullOrEmpty(initialFormattedValue.ToString) Then ctl.Text = initialFormattedValue.ToString
    199. ctl.DropDownStyle = CType(Me.OwningColumn, DepressComboBoxListColumn).DropDownStyle
    200. ctl.FlatStyle = CType(Me.OwningColumn, DepressComboBoxListColumn).FlatStyle
    201. '
    202. 'Liste dynamisch befüllen!
    203. If Not fillComboBoxList(ctl) Then Throw New ArgumentException("Datenauswertungsfehler in der ComboBoxListe")
    204. End Sub
    205. Public Overrides ReadOnly Property EditType() As Type
    206. ' Typ des Bearbeitungssteuerelementes vom DepressComboBoxListCell
    207. Get
    208. Return GetType(DepressComboBoxListEditingControl)
    209. End Get
    210. End Property
    211. Public Overrides ReadOnly Property ValueType() As Type
    212. Get
    213. Return GetType(String) ' Wertetyp vom DepressComboBoxListCell
    214. End Get
    215. End Property
    216. Public Overrides ReadOnly Property DefaultNewRowValue() As Object
    217. Get
    218. Return String.Empty
    219. End Get
    220. End Property
    221. Private Function fillComboBoxList(cbx As DepressComboBoxListEditingControl) As Boolean
    222. Dim col = TryCast(Me.OwningColumn, DepressComboBoxListColumn)
    223. If IsNothing(col) Then Return False ' Fehler im TryCast-DepressComboBoxListColum
    224. Dim colIndex = col.Index 'Bezugsspalte Index feststellen
    225. Dim colName = col.DataPropertyName 'Bezugsspalte DataPropertyName feststellen
    226. If String.IsNullOrEmpty(colName) Then Return False 'Fehler
    227. '
    228. Dim externList As New List(Of String)
    229. If IsNothing(col.DataSource) Then
    230. externList = col.Items
    231. Else
    232. If String.IsNullOrEmpty(col.ValueMember) Then Return False
    233. Dim bsData = DirectCast(col.DataSource, BindingSource)
    234. If IsNothing(bsData) Then Return False
    235. Dim dvData As DataView = TryCast(bsData.List, DataView)
    236. If IsNothing(dvData) Then Return False
    237. If col.ValueType IsNot dvData.Table.Columns(col.ValueMember).DataType Then Return False 'ungleiche Datentypen
    238. dvData.Table.AcceptChanges() 'alle zwischenzeitlich gemachten Änderungen an der Tabelle durchführen.
    239. For r = 0 To dvData.Table.Rows.Count - 1
    240. externList.Add(dvData.Table.Rows(r)(col.ValueMember).ToString)
    241. Next
    242. End If
    243. '
    244. externList.Sort()
    245. cbx.Items.Clear() 'ComboBoxListe leeren
    246. Dim bs = TryCast(Me.DataGridView.DataSource, BindingSource)
    247. If IsNothing(bs) Then Return False ' Fehler bei BindingSource-Cast
    248. Dim dv = TryCast(bs.List, DataView)
    249. If IsNothing(dv) Then Return False ' Fehler bei DataView-Cast
    250. For Each i In externList 'externe Liste abgleichen
    251. If Not String.IsNullOrEmpty(i) Then
    252. If Not findValue(dv, colName, i) Then cbx.Items.Add(i)
    253. End If
    254. Next
    255. clearDuplicate(cbx)
    256. Return True
    257. End Function
    258. Private Function findValue(dv As DataView, colName As String, v As String) As Boolean
    259. For row = 0 To dv.Table.Rows.Count - 1
    260. If v = dv.Table.Rows(row)(colName).ToString Then Return True
    261. Next
    262. Return False
    263. End Function
    264. Private Sub clearDuplicate(ByVal cbx As DepressComboBoxListEditingControl)
    265. If cbx.Items.Count <= 1 Then Return
    266. For i = cbx.Items.Count - 1 To 0 Step -1
    267. Dim e = cbx.Items(i).ToString
    268. For j = 0 To i - 1
    269. If e = cbx.Items(j).ToString Then cbx.Items.Remove(e)
    270. Next
    271. Next
    272. End Sub
    273. End Class ' DepressComboBoxListCell
    274. Class DepressComboBoxListEditingControl : Inherits ComboBox
    275. 'Definiert gemeinsame Funktionen für Steuerelemente, die sich innerhalb von Zellen einer DataGridView befinden.
    276. Implements IDataGridViewEditingControl
    277. '
    278. 'Dieser Teil ist wegen Überlänge des Beitrages im Dateianhang anzusehen
    279. '
    280. End Class 'DepressComboBoxListEditingControl

    Wer Interesse hat, kann oben im Expander Auszüge von den 3 Klassen durchstöbern und unten
    das vollständiges Demo herunterladen, das den derzeitigen Status (lauffähig) zeigt.
    Hier kann man in der Entwurfszeit bei den benutzerdefinierten Einstellungen
    (Datasource, Datamember, Valuemember bzw. Items-Auflistung und ComboBox-Styles)
    im Aufgaben-Propertyfenster (bei Spalten bearbeiten) herumspielen ...

    Die eingebauten Extensions stammen vom ErfinderDesRades :thumbup:

    Ich wäre sehr dankbar für Tipp's und Trick's zum Code etc. :)

    mfg
    VB1963
    Dateien

    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VB1963“ ()

    VB.NET-Quellcode

    1. dvData.Table.AcceptChanges() 'alle zwischenzeitlich gemachten Änderungen an der Tabelle durchführen.
    Du meinst wohl BindingSource.EndEdit.
    Table.AcceptChanges() greift ins Change-Tracking des Datasets ein, und verändert das Speicher-Verhalten.

    Aber gfällt mir gut das Teil. Bes., dass man da einfach im Designer paar Werte festverdrahtet reinschreiben kann, also so Enum-mäßig. Obwohl das sicher nicht die reine datenbänkerische Lehre is.
    Danke für deinen Tip :)
    Ich habe es mit bsData.EndEdit schon probiert gehabt,
    aber da erzeugt er in Zeile 262 eine Ausnahme bei gelöschten Datensätzen. :?:
    siehe angehängtes Bild
    Bilder
    • Ausnahme-1.jpg

      127,74 kB, 850×852, 126 mal angesehen

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „VB1963“ ()

    Ja, jetzt habe ich es bemerkt - die gelöschten Datenzeilen sind beim Laden wieder da - darauf habe ich noch gar nicht geachtet...

    Ich frage jetzt .RowState auf gelöschte Zeilen ab, soweit tut es jetzt wieder, wie es soll ...

    Spoiler anzeigen

    VB.NET-Quellcode

    1. bsData.EndEdit()
    2. For r = 0 To dvData.Table.Rows.Count - 1
    3. If dvData.Table.Rows(r).RowState = DataRowState.Deleted Then Continue For
    4. externList.Add(dvData.Table.Rows(r)(col.ValueMember).ToString)
    5. Next

    Danke nochmals