Neuerstellen eines umfangreichen Projektes - aus schlechtem Code mach guten Code
- VB.NET
Sie verwenden einen veralteten Browser (%browser%) mit Sicherheitsschwachstellen und können nicht alle Funktionen dieser Webseite nutzen.
Hier erfahren Sie, wie einfach Sie Ihren Browser aktualisieren können.
Hier erfahren Sie, wie einfach Sie Ihren Browser aktualisieren können.
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 -
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 registrierenRegisterNumericTextboxInput(tb1,tb2,....)
und fertig. Schon
kann da keiner mehr was anderes eingeben
VB.NET-Quellcode
- ''' <summary> Bewirkt, dass nur Zahlen in Textboxen akzeptiert werden. </summary>
- Public Sub RegisterNumericTextboxInput(ParamArray numericTextBoxes As TextBox())
- For Each ntb In numericTextBoxes
- AddHandler ntb.KeyDown, AddressOf TextBox_numericKeyDown
- AddHandler ntb.Enter, AddressOf TextBox_Enter
- AddHandler ntb.MouseClick, AddressOf TextBox_MouseDoubleClick
- AddHandler ntb.Leave, AddressOf TextBox_numericLeave
- Next
- End Sub
VB.NET-Quellcode
- Private Sub TextBox_MouseDoubleClick(sender As Object, e As EventArgs)
- Dim tb = DirectCast(sender, TextBox)
- tb.SelectAll()
- End Sub
- Private Sub TextBox_Enter(sender As Object, e As EventArgs)
- Dim tb = DirectCast(sender, TextBox)
- tb.SelectAll()
- End Sub
- Private Sub TextBox_numericKeyDown(sender As Object, e As KeyEventArgs)
- Dim tb = DirectCast(sender, TextBox)
- Select Case e.KeyCode
- Case Keys.Space : tb.Text = Date.Today.Year.ToString
- Case Keys.D0 To Keys.D9, Keys.NumPad0 To Keys.NumPad9, Keys.Back 'nur Ziffern und Backspace zulassen
- Case Keys.Shift, Keys.Home, Keys.End, Keys.Delete, Keys.Left, Keys.Right
- Case Else : e.SuppressKeyPress = True 'alle anderen Eingaben ablehnen
- End Select
- End Sub
- Private Sub TextBox_numericLeave(sender As Object, e As EventArgs)
- Dim tb = DirectCast(sender, TextBox)
- If tb.Text = "" Then tb.Text = "0"
- End Sub
"Na, wie ist das Wetter bei dir?"
"Caps Lock."
"Hä?"
"Shift ohne Ende!" -
tragl schrieb:
Für sowas hab ich Handling-Methoden gebastelt
Ich meinte damit, dass die Überprüfung der Benutzerdaten (noch) nicht fertig ist.
Aber nur Zahleningaben erlauben, finde ich auch spannend. Danke dafür! -
Ich find's ungünstig, dass die ganzen ComboBoxen beschreibbar sind. Da ist
Lieferant 1
voreingestellt, ich tragLieferant 08/15
ein und es wirdLieferant 1
übernommen. Da besser alle ComboBoxen auf DropDownStyleDropDownList
machen.
Warum ist dasUCArtikel
eigentlich nicht im UserControls-Ordner?
Was istName1
bei der Artikelneuanlage/-bearbeitung? Gibt es dann auch einenName2
?
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, stattSelectedArticle.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:
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?
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
- Public Class dlgLieferantBearbeiten
- Private _CreateNewSupplier As Boolean
- Private Sub dlgLieferantBearbeiten_Load(sender As Object, e As EventArgs) Handles MyBase.Load
- _CreateNewSupplier = Me.BSLieferant.At(Of DtsDaten.LieferantRow).RowState = DataRowState.Detached
- End Sub
- Private Sub BTNSave_Click(sender As Object, e As EventArgs) Handles BTNSave.Click
- Dim SupplierName = TBName.Text
- If _CreateNewSupplier AndAlso DtsDaten.Lieferant.SupplierExists(SupplierName) Then
- ShowAutoClosingMessageBox($"Der Lieferant {SupplierName} existiert bereits")
- Return
- End If
- SaveSupplier()
- End Sub
- End Class
- Partial Public Class LieferantDataTable
- Public Function SupplierExists(SupplierName As String) As Boolean
- Return Me.Any(Function(z) z.Name = SupplierName)
- End Function
- 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:
und prüfe entsprechend immer:
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
- Partial Public Class LieferantDataTable
- Public Function SupplierExists(SupplierName As String) As Boolean
- Return Me.Any(Function(z) z.Name = SupplierName)
- End Function
- Public Function SupplierExistsNew(SupplierName As String, SelectedSupplier As DtsDaten.LieferantRow) As Boolean
- Return Me.Any(Function(z) z.Name = SupplierName AndAlso z IsNot SelectedSupplier)
- End Function
- 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!" -
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:- Lieferantenneuanlage
- Lieferantenbearbeitung
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
- Sub AddNewSupplier()
- Dim NameForNewSupplier = GetNameForNewSupplierFromUser()
- If ComplainingAboutAlreadyExistingSupplierName(NameForNewSupplier) Then Return
- AddNewSupplierCalled(NameForNewSupplier)
- End Sub
- Function ComplainingAboutAlreadyExistingSupplierName(DesiredSupplierName As String) As Boolean
- If Not Tds.Suppliers.Any(Function(x) x.Name = DesiredSupplierName) Then Return False
- MessageBox.Show("Dieser Name ist bereits vergeben.")
- Return True
- End Function
und für 2.
VB.NET-Quellcode
- Sub EditCurrentSupplier(CurrentSupplier As Tds.SupplierRow)
- Dim NewNameForCurrentSupplier = GetNewNameForCurrentSupplierFromUser()
- If CurrentSupplier.Name = NewNameForCurrentSupplier OrElse ComplainingAboutAlreadyExistingSupplierName(NewNameForCurrentSupplier) Then Return
- CurrentSupplier.Name = NewNameForCurrentSupplier
- End Sub
- Function ComplainingAboutAlreadyExistingSupplierName(DesiredSupplierName As String) As Boolean
- If Not Tds.Suppliers.Any(Function(x) x.Name = DesiredSupplierName) Then Return False
- MessageBox.Show("Dieser Name ist bereits vergeben.")
- Return True
- 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. - Lieferantenneuanlage
-
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
- Public Class dlgWarengruppeBearbeiten
- Private _CreateNewWareGroup As Boolean
- Private _SelectedProductGroup As DtsDaten.WarengruppeRow
- Private Sub dlgWarengruppeBearbeiten_Load(sender As Object, e As EventArgs) Handles MyBase.Load
- _CreateNewWareGroup = Me.BSWarengruppe.At(Of DtsDaten.WarengruppeRow).RowState = DataRowState.Detached
- If Not _CreateNewWareGroup Then _SelectedProductGroup = Me.BSWarengruppe.At(Of DtsDaten.WarengruppeRow)
- End Sub
- Private Sub ValidateInputAndSaveProductGroup()
- '[...]
- If _CreateNewWareGroup Then
- If DtsDaten.Warengruppe.ProductGroupExists(ProductGroupName) Then
- ShowAutoClosingMessageBox($"Die Warengruppe {ProductGroupName} existiert bereits")
- Return
- End If
- Else
- If _SelectedProductGroup.Name <> ProductGroupName AndAlso DtsDaten.Warengruppe.ProductGroupExists(ProductGroupName) Then
- ShowAutoClosingMessageBox($"Die Warengruppe {ProductGroupName} existiert bereits")
- Return
- End If
- End If
- '[...]
- Me.DialogResult = DialogResult.OK
- End Sub
- Partial Public Class WarengruppeDataTable
- Public Function ProductGroupExists(ProductGroupName As String) As Boolean
- Return Me.Any(Function(z) z.Name = ProductGroupName)
- End Function
- 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 PropertyName
des BS-Currents. Stell erstmal aufNever
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.
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
- Partial Public Class ArtikelDataTable
- Public Function ArtNrExistsWithinASupplier(ArtNr As String, Supplier As LieferantRow) As Boolean
- Dim ArticleListBySupplier = Supplier.GetArtikelRows
- For Each article In ArticleListBySupplier
- If article.ArtNr = ArtNr Then Return True
- Next
- Return False
- End Function
- End Class
-
DerSmurf schrieb:
Aber leider funktioniert das speichern dann nicht mehr.
Mach ma ins FormClosing-Event einMe.ValidateChildren
rein
DerSmurf schrieb:
Kann man diese Funktion mit Linq vereinfachen?
Jo, sowas wieReturn ArticleListBySupplier.Any(Function(x)x.ArtNr = ArtNr)
"Na, wie ist das Wetter bei dir?"
"Caps Lock."
"Hä?"
"Shift ohne Ende!" -
-
-
Das sollte wohl klappen (auch wenn ich googlen müsste wie), aber dann frage ich mich, ob nicht meine Variante:
die bessere ist? -
DerSmurf schrieb:
auch wenn ich googlen müsste wie
Naja, im FormClosingOnValidation
wieder umstellen von Never auf den urspr. Wert. DanachMe.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!" -
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 auchPrivate _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.
-
Ähnliche Themen
-
Glubschi43 - - Sonstige Problemstellungen
-
6 Benutzer haben hier geschrieben
- DerSmurf (106)
- VaporiZed (79)
- tragl (17)
- ErfinderDesRades (10)
- petaod (1)
- Marcus Gräfe (1)