Neuerstellen eines umfangreichen Projektes - aus schlechtem Code mach guten Code

  • VB.NET

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

    Sodiho. Da mein alter Upload eh noch keinen Download hatte, hab ich die Zeit genutzt und das ganze ausformuliert.
    Wie ich die Form nun anzeige ist ja wurscht, den Code brauche ich so oder so.
    Also es ist nun alles fertig, außer das Überprüfen der Benutzereingabe beim speichern (wer also Text in Zahlenboxen schreibt, ist selbst schuld :o).

    Außerdem habe ich den Threadtitel mal angepasst. Der alte stimmt ja schon lange nicht mehr xD
    Dateien
    • Theo.zip

      (1,22 MB, 32 mal heruntergeladen, zuletzt: )

    DerSmurf schrieb:

    wer also Text in Zahlenboxen schreibt, ist selbst schuld :o


    Für sowas hab ich Handling-Methoden gebastelt... beim Öffnen der Form (FormLoad) einfach die Textboxen registrieren RegisterNumericTextboxInput(tb1,tb2,....) und fertig. Schon
    kann da keiner mehr was anderes eingeben

    VB.NET-Quellcode

    1. ''' <summary> Bewirkt, dass nur Zahlen in Textboxen akzeptiert werden. </summary>
    2. Public Sub RegisterNumericTextboxInput(ParamArray numericTextBoxes As TextBox())
    3. For Each ntb In numericTextBoxes
    4. AddHandler ntb.KeyDown, AddressOf TextBox_numericKeyDown
    5. AddHandler ntb.Enter, AddressOf TextBox_Enter
    6. AddHandler ntb.MouseClick, AddressOf TextBox_MouseDoubleClick
    7. AddHandler ntb.Leave, AddressOf TextBox_numericLeave
    8. Next
    9. End Sub


    VB.NET-Quellcode

    1. Private Sub TextBox_MouseDoubleClick(sender As Object, e As EventArgs)
    2. Dim tb = DirectCast(sender, TextBox)
    3. tb.SelectAll()
    4. End Sub
    5. Private Sub TextBox_Enter(sender As Object, e As EventArgs)
    6. Dim tb = DirectCast(sender, TextBox)
    7. tb.SelectAll()
    8. End Sub
    9. Private Sub TextBox_numericKeyDown(sender As Object, e As KeyEventArgs)
    10. Dim tb = DirectCast(sender, TextBox)
    11. Select Case e.KeyCode
    12. Case Keys.Space : tb.Text = Date.Today.Year.ToString
    13. Case Keys.D0 To Keys.D9, Keys.NumPad0 To Keys.NumPad9, Keys.Back 'nur Ziffern und Backspace zulassen
    14. Case Keys.Shift, Keys.Home, Keys.End, Keys.Delete, Keys.Left, Keys.Right
    15. Case Else : e.SuppressKeyPress = True 'alle anderen Eingaben ablehnen
    16. End Select
    17. End Sub
    18. Private Sub TextBox_numericLeave(sender As Object, e As EventArgs)
    19. Dim tb = DirectCast(sender, TextBox)
    20. If tb.Text = "" Then tb.Text = "0"
    21. End Sub
    "Na, wie ist das Wetter bei dir?"
    "Caps Lock."
    "Hä?"
    "Shift ohne Ende!" :thumbsup:
    Ich find's ungünstig, dass die ganzen ComboBoxen beschreibbar sind. Da ist Lieferant 1 voreingestellt, ich trag Lieferant 08/15 ein und es wird Lieferant 1 übernommen. Da besser alle ComboBoxen auf DropDownStyle DropDownList machen.
    Warum ist das UCArtikel eigentlich nicht im UserControls-Ordner?
    Was ist Name1 bei der Artikelneuanlage/-bearbeitung? Gibt es dann auch einen Name2?
    Sollen die ganzen DGV-Rows-höhenverstellbar sein? Ich deaktivier das immer.
    Ve ist wohl Verpackungseinheit. Brauch es da eigentlich ne Einheit?
    Wozu speicherst Du eigentlich Deine Daten in _AlteMarge und so, also in extra Variablen? Ist doch alles in der tDS-Row drin.
    Arbeitest Du eigentlich mit DataBinding? Du schiebst die Daten immer manuell von tDS-Row ins Form und zurück. Absicht?
    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.
    Moin und erstmal wieder Danke! fürs drübergucken.

    Edit: @VaporiZed Sorry, für die Kurzantwort. Nun siehts zeitlich bei mir etwas besser aus, hier also nun ein gescheiter Post von mir:
    DropDownList habe ich bisher immer ignoriert, weil ich dachte, man kann ja in die graue ComboBox dann garnicht schreiben - also nicht nur mit der Tastatur eine Auswahl treffen.
    Bisher habe ich es so gehandhabt, dass der User eintragen kann was er will, und beim speichern wird geprüft, ob der Eintrag gültig ist, oder es kommt eine Meldung.
    Aber gerade habe ich festgestellt, dass eine Auswahl, nur mit der Tastatur, ja genauso möglich ist, wie beim Style DropDown. Ich stelle also alle ComboBoxen entsprechend um, und spare mir die Prüfung.

    Ich habe immer alle Controls (und die frmHaupt), an denen ich gerade arbeite, im Hauptordner. Sobald diese fertig sind, verschiebe ich wos hingehört.

    Im DataSet hatte jeder Artikel die Rows Name1 und Name2. Name2 wird für unwichtigere Dinge verwendet, wie z.B. Name1 = Hundebett Fluffelwuff 80cm | Name2 = 80x35x40cm
    Dies habe ich nun im Dts in Name und Zusatz umbenannt. Edit: und gerade habe ich mir überlegt, dass Namenszusatz wohl besser wäre.
    Also aus Name1 wird Name und aus Name2(aka Zusatz) wird Namenszusatz.

    Ich wusste nicht, dass man die Höhenverstellbarkeit von DGV Rows verbieten kann. AllowUserToResizeRows steht jetzt aber in allen DGVs auf False - find ich ziemlich cool.

    Ve ist Verpackungseinheit. Aber ich verstehe nicht, was du hier mit Einheit meinst?
    Wenn ich einen Artikel habe mit Ve = x, dann bekomme ich x Stück, wenn ich 1 Ve bestelle.

    Und zu den letzten beiden Punkten. Zum extra speichern der Daten; Ich dachte mir, es wird im Code übersichtlicher, wenn ich die Variablen _AlteMarge, _AlterVK, _AlterEK verwende, statt SelectedArticle.Marge, usw.
    Hier hatte ich Sorge vor Unklarheit, warum ich z.B. TBVK.Text mit SelectedArticle.VK vergleiche. _AlterVK erschien mir da passender.
    Auf dieser Form arbeite ich an keiner Stelle mit DataBinding zu den Artikeln (nur die ComboBoxen für Lieferant, Warengruppe und Kategorie haben logischerweise ein Binding). Ich möchte diese Form gerne nicht modal angezeigt haben, damit ich im Hintergrund noch im Programm rumklicken kann.
    Es wird auf der UCArtikel später noch einen WebView2 geben, mit dem Rechnungen (im pdf Format) angezeigt werden können, um z.B. angenehmer neue Artikel anlegen zu können.
    So ist es möglich den Bildschirm leicht horizontal zu teilen (statt vertikal, wie es mit Windows möglich ist, wenn ich ein Programm gegen den Rand klatsche). Diese vertikale Teilung eignet sich nur bedingt für diese Anzeige, so dass ich vor dem WebView2 Einbau im alten Programm, die beiden Fenster (mein Programm und die Rechnungspdf) händisch untereinander angeordnet habe. (was schon mit der Maus keinen Spaß macht und mit dem Finger erst recht nicht)
    Das Problem ist nun, mit einer modalen Artikelform, dass ich eben nicht in die Rechnung klicken kann, wenn ich einen Artikel bearbeite (z.B. zum kopieren eines EAN Codes, oder zum scrollen). Das finde ich an meinem jetzigen Programm nervig.
    Ich habe aber keinen Weg gefunden sinnvoll DataBinding auf einer non modalen Form hinzubekommen. Daher habe ich mich entschieden das DataBinding weg zu lassen und die Daten manuell zu schreiben.
    Hier ist nun die Frage, ist meine herangehensweise hier so ok, oder sollte ich das was anders machen?

    Edit: Ich bin mir nicht sicher ob ich die Begrifflichkeiten modal und non modal richtig verwendet habe.
    In meiner Welt: modale Form und ich kann nicht in der aufrufenden Form umherklicken | nicht modal: wenn die offen ist, kann ich nach wie vor, machen was ich will.
    Ich hoffe, dass ist in eurer Welt genau so :)

    Edit: @tragl
    Deine NumericTextBoxen habe ich etwas modifiziert und eingebaut. Case Keys.Space : tb.Text = Date.Today.Year.ToString Diese Zeile finde ich komisch. Wenn ich Leertaste drücke, ist die Box nicht mehr numeric?
    Du erlaubst den Tastendruck Shift. Aber es gibt doch mit dieser Taste keine Zahl?
    Und ich wollte das selektieren des gesamten Textes beim klicken in die Box unterbinden. Dabei ist mir der kleine Fehler in der Benennung deiner Sub aufgefallen:

    VB.NET-Quellcode

    1. AddHandler ntb.MouseClick, AddressOf TextBox_MouseDoubleClick

    MouseClick, Adressof MouseDoubleClick
    Außerdem habe ich noch eine Prüfung eingebaut, dass genau ein Komma eingegeben werden darf. Geht das evtl. auch als Einzeiler in der Select Case Anweisung?

    VB.NET-Quellcode

    1. Case Keys.Decimal
    2. If tb.Text.Contains(",") Then e.SuppressKeyPress = True

    Dieser Beitrag wurde bereits 11 mal editiert, zuletzt von „DerSmurf“ ()

    Und noch eine konkrete Frage zum Code. Ich habe festgestellt, dass meine Prüfungen, ob etwas im Dts schon exisitiert unzureichend ist. Z.B. hier: (auf der Form dlgLieferantBearbeiten)

    VB.NET-Quellcode

    1. Public Class dlgLieferantBearbeiten
    2. Private _CreateNewSupplier As Boolean
    3. Private Sub dlgLieferantBearbeiten_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    4. _CreateNewSupplier = Me.BSLieferant.At(Of DtsDaten.LieferantRow).RowState = DataRowState.Detached
    5. End Sub
    6. Private Sub BTNSave_Click(sender As Object, e As EventArgs) Handles BTNSave.Click
    7. Dim SupplierName = TBName.Text
    8. If _CreateNewSupplier AndAlso DtsDaten.Lieferant.SupplierExists(SupplierName) Then
    9. ShowAutoClosingMessageBox($"Der Lieferant {SupplierName} existiert bereits")
    10. Return
    11. End If
    12. SaveSupplier()
    13. End Sub
    14. End Class
    15. Partial Public Class LieferantDataTable
    16. Public Function SupplierExists(SupplierName As String) As Boolean
    17. Return Me.Any(Function(z) z.Name = SupplierName)
    18. End Function
    19. End Class


    Wenn ich nun einen Lieferanten bearbeite, ist _CreateNewSupplier False und die Prüfung wird nicht ausgeführt. Ich kann also in einen Namen ändern, den es bereits gibt.
    Die Prüfung muss also immer durchgeführt werden, egal ob beim Neuanlegen, oder beim Bearbeiten. Also gebe ich einfach die SelectedSupplierRow mit:

    VB.NET-Quellcode

    1. Public Function SupplierExistsNew(SupplierName As String, SelectedSupplier As DtsDaten.LieferantRow) As Boolean
    2. Return Me.Any(Function(z) z.Name = SupplierName AndAlso z IsNot SelectedSupplier)
    3. End Function

    und prüfe entsprechend immer:

    VB.NET-Quellcode

    1. If DtsDaten.Lieferant.SupplierExistsNew(SupplierName, Me.BSLieferant.At(Of DtsDaten.LieferantRow)) Then


    Es gibt aber andere Stellen, da möchte ich prüfen ob es einen Lieferanten gibt (z.B. beim anlegen eines neuen Artikels - mit der alten ComboBox Einstellung), ohne dass ich eine entsprechende Row mitgeben könnte.
    Wie mache ich aus diesen beiden Prüfungen eine einzige, die ich eben mit dem Parameter SelectedSupplier aufrufen kann und ohne?

    VB.NET-Quellcode

    1. Partial Public Class LieferantDataTable
    2. Public Function SupplierExists(SupplierName As String) As Boolean
    3. Return Me.Any(Function(z) z.Name = SupplierName)
    4. End Function
    5. Public Function SupplierExistsNew(SupplierName As String, SelectedSupplier As DtsDaten.LieferantRow) As Boolean
    6. Return Me.Any(Function(z) z.Name = SupplierName AndAlso z IsNot SelectedSupplier)
    7. End Function
    8. End Class

    Einfach nothing übergeben, weil dann die zweite Bedingung immer False ist?
    Oder bin ich komplett auf dem Holzweg und habe hier einen dicken Denkfehler in der Prüfung an sich?

    DerSmurf schrieb:

    Diese Zeile finde ich komisch. Wenn ich Leertaste drücke, ist die Box nicht mehr numeric?

    Doch, wird doch nur das Jahr eingetragen?

    DerSmurf schrieb:

    Du erlaubst den Tastendruck Shift. Aber es gibt doch mit dieser Taste keine Zahl?

    muss ich mir anschauen, kommt mir grad auch spanisch vor

    DerSmurf schrieb:

    Und ich wollte das selektieren des gesamten Textes beim klicken in die Box unterbinden. Dabei ist mir der kleine Fehler in der Benennung deiner Sub aufgefallen:

    jo da hab ich vermutlich irgendwann was geändert

    Ich überarbeite den Block mal, kann dir dann ggf. meine anderen "Textbox-Handler" auch mal zur Verfügung stellen. Hab da auch welche für Decimal, Datum etc. gebaut.
    "Na, wie ist das Wetter bei dir?"
    "Caps Lock."
    "Hä?"
    "Shift ohne Ende!" :thumbsup:
    Ich stimme mit Deiner Verwendung der Begrifflichkeiten modal/nicht-modal überein.
    Aber mir geht grad überhaupt nicht in den Kopf, wo Du jetzt das Problem oder besser den Zusammenhang zwischen DataBinding und Modalität eines Forms siehst. Das eine hat doch mit dem anderen gar nix zu tun.
    Das mit dem Supplier versteh ich nicht ganz. Warum willst Du überhaupt die beiden Methoden zu einer zusammenfassen? In meinen Programmen hätte ich 2 Funktionen:
    1. Lieferantenneuanlage
    2. Lieferantenbearbeitung
    Bei 1 frag ich nach dem Namen und mach dann die Prüfung, ob der schon vergeben ist.
    Bei 2 frag ich nach dem Namen, wenn der gleich dem des zu bearbeitenden Lieferanten ist, passiert nix, sonst eben schauen, ob schon vergeben, dann auch meckern.
    ->

    VB.NET-Quellcode

    1. Sub AddNewSupplier()
    2. Dim NameForNewSupplier = GetNameForNewSupplierFromUser()
    3. If ComplainingAboutAlreadyExistingSupplierName(NameForNewSupplier) Then Return
    4. AddNewSupplierCalled(NameForNewSupplier)
    5. End Sub
    6. Function ComplainingAboutAlreadyExistingSupplierName(DesiredSupplierName As String) As Boolean
    7. If Not Tds.Suppliers.Any(Function(x) x.Name = DesiredSupplierName) Then Return False
    8. MessageBox.Show("Dieser Name ist bereits vergeben.")
    9. Return True
    10. End Function


    und für 2.

    VB.NET-Quellcode

    1. Sub EditCurrentSupplier(CurrentSupplier As Tds.SupplierRow)
    2. Dim NewNameForCurrentSupplier = GetNewNameForCurrentSupplierFromUser()
    3. If CurrentSupplier.Name = NewNameForCurrentSupplier OrElse ComplainingAboutAlreadyExistingSupplierName(NewNameForCurrentSupplier) Then Return
    4. CurrentSupplier.Name = NewNameForCurrentSupplier
    5. End Sub
    6. Function ComplainingAboutAlreadyExistingSupplierName(DesiredSupplierName As String) As Boolean
    7. If Not Tds.Suppliers.Any(Function(x) x.Name = DesiredSupplierName) Then Return False
    8. MessageBox.Show("Dieser Name ist bereits vergeben.")
    9. Return True
    10. End Function
    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. Stimmt, das mit der Prüfung klingt plausibel.
    Werd ich dann wieder ummodeln :o)

    Zur Geschichte mit dem Binding bastel ich mal eine Demo und schmeiß sie ran.

    Aber kannst du mir die Frage beantworten, ob ichs grundsätzlich so machen kann wie ich gerade dabei bin, also ohne Binding?
    Oder ob ich ein Binding unbedingt einbauen sollte?
    Binding spart Dir einfach nur ne Menge Eigencode. Das ist der wesentliche Punkt (für mich).
    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.
    Guten Morgen
    Die Urlaubszeit ist vorbei (zumindest sind die meisten meiner Leute wieder im Laden), sodass meine Tage hoffentlich wieder etwas kürzer werden und ich nicht Ewigkeiten für eine Antwort brauche.
    Habe immer ein schlechtes Gewissen, wenn ich hier mega Hilfe bekomme und dann Tagelang brauche, etwas umzusetzen, oder mich zurück zu melden. Also sorry dafür!

    Zu der Prüfung. Ich bekomms nicht hin...
    Habe nun mit der Warengruppe angefangen (weils die unterste Datei im Ordner ist), aber das Prozedere ist identisch mit den Lieferante.
    Da ich hier die Helpers nutze (und damit die Form vor dem Aufruf nicht instanziiere, kann ich keinen Parameter (keinen Warengruppennamen) mitgeben.
    Also hab ichs so versucht:

    VB.NET-Quellcode

    1. ​Public Class dlgWarengruppeBearbeiten
    2. Private _CreateNewWareGroup As Boolean
    3. Private _SelectedProductGroup As DtsDaten.WarengruppeRow
    4. Private Sub dlgWarengruppeBearbeiten_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    5. _CreateNewWareGroup = Me.BSWarengruppe.At(Of DtsDaten.WarengruppeRow).RowState = DataRowState.Detached
    6. If Not _CreateNewWareGroup Then _SelectedProductGroup = Me.BSWarengruppe.At(Of DtsDaten.WarengruppeRow)
    7. End Sub
    8. Private Sub ValidateInputAndSaveProductGroup()
    9. '[...]
    10. If _CreateNewWareGroup Then
    11. If DtsDaten.Warengruppe.ProductGroupExists(ProductGroupName) Then
    12. ShowAutoClosingMessageBox($"Die Warengruppe {ProductGroupName} existiert bereits")
    13. Return
    14. End If
    15. Else
    16. If _SelectedProductGroup.Name <> ProductGroupName AndAlso DtsDaten.Warengruppe.ProductGroupExists(ProductGroupName) Then
    17. ShowAutoClosingMessageBox($"Die Warengruppe {ProductGroupName} existiert bereits")
    18. Return
    19. End If
    20. End If
    21. '[...]
    22. Me.DialogResult = DialogResult.OK
    23. End Sub
    24. Partial Public Class WarengruppeDataTable
    25. Public Function ProductGroupExists(ProductGroupName As String) As Boolean
    26. Return Me.Any(Function(z) z.Name = ProductGroupName)
    27. End Function
    28. End Class


    Aber die erste Bedingung meiner AndAlso Abfrage ist immer False! ​If _SelectedProductGroup.Name <> ProductGroupName
    Wenn ich das schrittweise durchlaufen lasse, sehe ich, dass ​_SelectedProductGroup.name immer dem Text in TBName (also dem neuen Warengruppennamen) entspricht. Obwohl ich ​_SelectedProductGroup ausschließlich im Form Load Event beschreibe.
    Du hast n DataBinding mit Datenquellen-Aktualisierungsmodus OnValidation an der TextBox. Daher bearbeitest Du immer die Property Name des BS-Currents. Stell erstmal auf Never um, damit der aktuelle Name beim DialogStart angezeigt, aber nicht automatisch in der Datenquelle aktualisiert wird, wenn Du den TextBox-Text änderst.
    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.
    Das löst mein Kontrolleproblem. Aber leider funktioniert das speichern dann nicht mehr.
    Wenn ich eine neue Warengruppe anlege, bleibt der Name leer.
    Ich speichere im Load Event mal den Namen, nicht die Row, das sollte ja klappen.

    VB.NET-Quellcode

    1. Private _OldProductGroupName As String
    2. Private Sub LoadEvent
    3. If Not _CreateNewWareGroup Then _OldProductGroupName = Me.BSWarengruppe.At(Of DtsDaten.WarengruppeRow).Name
    4. End Sub


    Edit: Jo, das geht. Was hälst du davon?

    und Edit2: ich bin parallel dabei meine Artikelform zu beenden, damit ich die angesprochene Demo hochladen kann (wegen Binding ja/nein).
    Kann man diese Funktion mit Linq vereinfachen?

    VB.NET-Quellcode

    1. Partial Public Class ArtikelDataTable
    2. Public Function ArtNrExistsWithinASupplier(ArtNr As String, Supplier As LieferantRow) As Boolean
    3. Dim ArticleListBySupplier = Supplier.GetArtikelRows
    4. For Each article In ArticleListBySupplier
    5. If article.ArtNr = ArtNr Then Return True
    6. Next
    7. Return False
    8. End Function
    9. End Class

    DerSmurf schrieb:

    Aber leider funktioniert das speichern dann nicht mehr.

    Mach ma ins FormClosing-Event ein Me.ValidateChildren rein

    DerSmurf schrieb:

    Kann man diese Funktion mit Linq vereinfachen?

    Jo, sowas wie Return ArticleListBySupplier.Any(Function(x)x.ArtNr = ArtNr)
    "Na, wie ist das Wetter bei dir?"
    "Caps Lock."
    "Hä?"
    "Shift ohne Ende!" :thumbsup:
    Habe ich schon versucht - brachte keinen Erfolg.
    Also ich hatte es nicht im Closing, sondern in der Sub, welche den Userinput kontrolliert und die Form mittels: Me.DialogResult = DialogResult.OK schließt.
    Aber das Ergebnis sollte ja das gleiche sein.
    Das sollte wohl klappen (auch wenn ich googlen müsste wie), aber dann frage ich mich, ob nicht meine Variante:

    VB.NET-Quellcode

    1. Private _OldProductGroupName As String
    2. Private Sub LoadEvent
    3. If Not _CreateNewWareGroup Then _OldProductGroupName = Me.BSWarengruppe.At(Of DtsDaten.WarengruppeRow).Name
    4. End Sub

    die bessere ist?

    DerSmurf schrieb:

    auch wenn ich googlen müsste wie


    Naja, im FormClosing OnValidation wieder umstellen von Never auf den urspr. Wert. Danach Me.ValidateChildren und dann sollte das auch passen. Aber erklär' nochmal, was
    du genau bezwecken willst? Es gibt ne Textbox, da kann jemand ne Warengruppe eingeben. Es soll dann geprüft werden ob's die schon gibt? Was ist, wenn jemand nen Tippfehler macht?
    Also statt "Testwarengruppe" (die gibt's schon), "Tetwarengruppe" eingibt. Dann wäre die urspr. gemeint, wird aber neu angelegt, weil nicht gefunden... versteh' nicht so ganz was du damit bezwecken willst?
    "Na, wie ist das Wetter bei dir?"
    "Caps Lock."
    "Hä?"
    "Shift ohne Ende!" :thumbsup:
    Der Zweck ist, dass eine Warengruppe eindeutig sein muss. "Testwarengruppe" darf es genau einmal geben.
    Wenn der User eine neue anlegt und die "Tetwarengruppe" nennt - also mit Tippfehler - bin ich damit fein.
    Es muss nur gewährleistet sein, dass ein Warengruppenname einmalig ist.
    Und das in Verbindung mit den Helpers vom @ErfinderDesRades - also mit EditNew(of ...) und editcurrent(of ...).

    Die Schwierigkeit war nun eine geeignete Prüfung zu entwerfen. da oben beschriebene Prüfung (Post 132) daran scheitert, dass eben das Datenquellenaktualisierungsintervall NICHT auf never steht.
    Ein Ändern des Textes in TBName ändert eben auch Private _SelectedProductGroup As DtsDaten.WarengruppeRow (auch wenn ich nach wie vor nicht verstehe warum, denn ich beschreibe sie ja im Load Event)

    Daher meine Idee einfach nicht die _SelectedProductGroup zu speichern, welche sich ja scheinbar ändert, sondern eben deren .Name Eigenschaft als string (der sich dann nicht mehr ändert) - Post 138.

    Das Funktioniert. Aber funktionierender Code von mir, ist ja nicht immer guter Code.