Ich hatte vor ein paar Monaten schon erste Schritte bzgl. einer typisierten BindingSource (im weiteren tBS) gemacht. Da diese sich bisher ganz gut bewährt hat, hier das, was ich mir bis dato zusammengeschustert habe.
Hauptdeklaration
API
Properties
Extensions, die mir auch in anderen Projekten das Leben leichter machen
Einsatzbeispiel:
Mehr an Code ist es im jeweiligen Einsatzprojekt erstmal nicht. Daher kann man beim Einsatz mehrerer tBSs diese auch alle in eine eigene Datei untereinander schreiben, eine tBS pro Zeile.
Das Projekt kompiliert man und schon tauchen die tBSs in der Toolbox auf und sind einsatzbereit:
Nun kann man diese zzgl. einem DGV auch gleich auf's Form ziehen, das DGV an eine tBS koppeln und schon sieht man (im Falle der
Der nächste Schritt - wie bei einer normalen BS (die ich im weiteren uBS für untypisierte BindingSource abkürze) - ist die Datenzuordnung:
bei der zweiten Zeile sieht man schon den ersten Vorteil der tBS:
Man muss ein Objekt vom Typ
Bei einer uBS würde man erst zur Laufzeit eine
Nächster Vorteil:
Will man den aktuell ausgewählten BS-Eintrag im verwenden, muss man bei einer uBS erstmal casten, bei einer tBS natürlich nicht, denn Current ist ja auch schon vom angegebenen Typ:
Die anderen Kleinigkeiten können direkt aus der Codedokumentation oder m.E. gar aus dem Code selbst entnommen werden.
Das ganze kann man sicherlich auch für tDS-gekoppelte BindingSources weiterspinnen, um sich den Doppelcast von Object->DataRowView->typisierte DataRow zu ersparen. Aber das mach ich vielleicht später.
##########
In der Property
##########
03.10.2022: Konstruktoren um
VB.NET-Quellcode
- '''<summary>eine typisierte BindingSource</summary>
- '''<typeparam name="T">der übergebende Datentyp, der bei New hinterlegt, bei Add benötigt und bei Current zurückgegeben wird</typeparam>
- '''<remarks>Um dieses Control auf einem Form zu verwenden, muss von dieser einfach geerbt werden, z.B.:
- '''<code>
- '''Public Class MyTypedBindingSource : Inherits TypedBindingSource(Of MyOwnClass) : End Class
- '''</code>
- ''' </remarks>
- Public MustInherit Class TypedBindingSource(Of T) : Inherits BindingSource
- '''<summary>erstellt eine typisierte BindingSource für den Typ T</summary>
- Protected Sub New(Components As ComponentModel.IContainer)
- DataSource = GetType(T)
- If Components IsNot Nothing Then Components.Add(Me)
- End Sub
- End Class
VB.NET-Quellcode
- Partial Class TypedBindingSource(Of T)
- '''<summary>fügt der Auflistung ein neues Element vom Typ T hinzu</summary>
- '''<param name="NewItem">das hinzuzufügende Item</param>
- Public Shadows Sub Add(NewItem As T)
- MyBase.Add(NewItem)
- End Sub
- '''<summary>entfernt das momentan ausgewählte Element der Auflistung; danach wird ein BindingReset für das GUI durchgeführt; wenn die Auflistung leer ist, passiert nichts</summary>
- Public Shadows Sub RemoveCurrent()
- If HasNoCurrent Then Return
- MyBase.RemoveCurrent()
- ResetBindings(False)
- End Sub
- '''<summary>ersetzt das ausgewählte Element durch ein anderes; danach wird ein Einzel-BindingReset für das GUI durchgeführt</summary>
- '''<param name="Replacement">das Element, welches an der ausgewählten Position den Platz einnehmen soll</param>
- Public Sub ReplaceCurrentWith(Replacement As T)
- If HasNoCurrent Then Return
- MyBase.Item(Position) = Replacement
- ResetCurrentItem()
- End Sub
- '''<summary>fügt der Auflistung die Elemente einer Liste hinzu; danach wird ein BindingReset für das GUI durchgeführt</summary>
- '''<param name="List">die Liste der Elemente, die hinzugefügt werden soll</param>
- Public Sub AddRange(List As IEnumerable(Of T))
- List.ForEach(Sub(x) Add(x))
- ResetBindings(False)
- End Sub
- '''<summary>ersetzt die Auflistung durch eine andere; danach wird ein BindingReset für das GUI durchgeführt</summary>
- '''<param name="List">die Liste der Elemente, die danach die TypedBindingSource-Auflistung darstellt</param>
- Public Sub ReplaceListBy(List As IEnumerable(Of T))
- Uncouple()
- DataSource = List
- Couple()
- End Sub
- '''<summary>ersetzt die Auflistungselemente durch andere; danach wird ein BindingReset für das GUI durchgeführt</summary>
- '''<param name="List">die Liste der Elemente, die sich danach in der Auflistung befinden</param>
- Public Sub ReplaceListContentBy(List As IEnumerable(Of T))
- Clear()
- AddRange(List)
- End Sub
- End Class
VB.NET-Quellcode
- Partial Class TypedBindingSource(Of T)
- '''<summary>ruft das Element an der angegebenen Position ab oder legt dieses fest; nach der Festlegung wird ein BindingReset für das GUI durchgeführt</summary>
- ''' <param name="Index">die Position innerhalb der Liste</param>
- ''' <returns>das Element an der angegebenen Position</returns>
- Default Public Shadows Property Item(Index As Integer) As T
- Get
- If Not IndexIsValid(Index) Then Return Nothing
- Return DirectCast(MyBase.Item(Index), T)
- End Get
- Set
- If Not IndexIsValid(Index) Then Return
- MyBase.Item(Index) = Value
- ResetBindings(False)
- End Set
- End Property
- '''<summary>ruft das aktuell ausgewählte Item ab oder legt dieses fest</summary>
- Public Shadows Property Current As T
- Get
- Return DirectCast(MyBase.Current, T)
- End Get
- Set
- If IsBindingSuspended OrElse HasNoCurrent OrElse Value.NotExists Then Return
- For i = 0 To Count - 1
- If Item(i).Equals(Value) Then Position = i : Exit For
- Next
- End Set
- End Property
- '''<summary>gibt wieder, ob die TypedBindingSource befüllt ist</summary>
- Public ReadOnly Property HasCurrent() As Boolean
- Get
- Return Position > -1 AndAlso Not Current.NotExists
- End Get
- End Property
- '''<summary>gibt wieder, ob die TypedBindingSource leer ist</summary>
- Public ReadOnly Property HasNoCurrent() As Boolean
- Get
- Return Not HasCurrent
- End Get
- End Property
- '''<summary>gibt wieder, ob die aktuelle Position 0 ist</summary>
- Public ReadOnly Property IsAtListStart() As Boolean
- Get
- Return Position = 0
- End Get
- End Property
- '''<summary>gibt wieder, ob die aktuelle Position am Ende der Liste ist</summary>
- Public ReadOnly Property IsAtListEnd() As Boolean
- Get
- Return Position = List.Count - 1
- End Get
- End Property
- End Class
VB.NET-Quellcode
- <Extension> Public Sub ForEach(Of T)(IEnumerable As IEnumerable(Of T), Action As Action(Of T))
- For Each Element In IEnumerable
- Action(Element)
- Next
- End Sub
- <Extension> Public Function NotExists([Object] As Object) As Boolean
- Return [Object] Is Nothing
- End Function
- <Extension> Public Function IsBetween(Of T As IComparable)(Thing As T, LowerBoundary As T, UpperBoundary As T) As Boolean
- Return Thing.CompareTo(LowerBoundary) >= 0 AndAlso Thing.CompareTo(UpperBoundary) <= 0
- End Function
Einsatzbeispiel:
VB.NET-Quellcode
- Public Class BsFileInfos : Inherits TypedBindingSource(Of IO.FileInfo)
- Sub New(Components As ComponentModel.IContainer)
- MyBase.New(Components)
- End Sub
- End Class
- Public Class BsTowers : Inherits TypedBindingSource(Of Tower)
- Sub New(Components As ComponentModel.IContainer)
- MyBase.New(Components)
- End Sub
- End Class
Mehr an Code ist es im jeweiligen Einsatzprojekt erstmal nicht. Daher kann man beim Einsatz mehrerer tBSs diese auch alle in eine eigene Datei untereinander schreiben, eine tBS pro Zeile.
Das Projekt kompiliert man und schon tauchen die tBSs in der Toolbox auf und sind einsatzbereit:
Nun kann man diese zzgl. einem DGV auch gleich auf's Form ziehen, das DGV an eine tBS koppeln und schon sieht man (im Falle der
BsFileInfos
-Instanz) eine leere FileInfo
-Tabelle:Der nächste Schritt - wie bei einer normalen BS (die ich im weiteren uBS für untypisierte BindingSource abkürze) - ist die Datenzuordnung:
bei der zweiten Zeile sieht man schon den ersten Vorteil der tBS:
Man muss ein Objekt vom Typ
Tower
einfügen. Alles andere wird abgelehnt.Bei einer uBS würde man erst zur Laufzeit eine
System.InvalidOperationException
bekommen.Nächster Vorteil:
Current
Will man den aktuell ausgewählten BS-Eintrag im verwenden, muss man bei einer uBS erstmal casten, bei einer tBS natürlich nicht, denn Current ist ja auch schon vom angegebenen Typ:
Die anderen Kleinigkeiten können direkt aus der Codedokumentation oder m.E. gar aus dem Code selbst entnommen werden.
Das ganze kann man sicherlich auch für tDS-gekoppelte BindingSources weiterspinnen, um sich den Doppelcast von Object->DataRowView->typisierte DataRow zu ersparen. Aber das mach ich vielleicht später.
##########
In der Property
HasCurrent()
war ein Fehler. Es darf narürlich nicht heißen: AndAlso Current.NotExists
, sondern AndAlso Not Current.NotExists
; alternativ verwende ich bei mir eine Extra-Extension namens Exists()
, aber die kollidiert etwas mit der gleichnamigen Funktion aus dem IO
-Namespace.##########
03.10.2022: Konstruktoren um
components
ergänzt, damit die tBS automatisch zu den Form-Components hinzugefügt und automatisch disposed wird. 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.
Dieser Beitrag wurde bereits 6 mal editiert, zuletzt von „VaporiZed“ ()