Neuerstellen eines umfangreichen Projektes - aus schlechtem Code mach guten Code

  • VB.NET

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

    DerSmurf schrieb:

    Zwar habe ich ihn mit UCs Klassenweise getrennt, aber getrennt habe ich ihn jetzt (mit #Regions) auch.
    Wo ist dann der Vorteil einer UC Lösung?
    Naja - es ist ja nicht nur klassenweise getrennt, sondern vor allem Zuständigkeits-weise ("segregation of responsibility").
    Also vorher hast du ein frmMain mit 5500 Zeilen Code, und irgendwo darin wird auch das AddressTab bespielt.
    Mit Ucls hast du nun ein uclAddressen, mit mw. 500 Zeilen, die sich genau um Address-Dinge kümmern, und nix anderes.
    Das ist ein Quantensprung an Wartbarkeit: Du siehst im SolutionExplorer deine Ucls und weisst sofort, wo welcher Code hingehört / wo er zu finden ist.
    Du öffnest die Datei und hast auf Anhieb (500 Zeilen sind ja noch übersichtlich) im Blick, was vor sich geht.
    Ich muss doch nochmal nerven.
    Meine im Designer erstellte UserControl heißt UCAdressen.
    Wenn ich diese nun auf die Form ziehe, würde ich sie dort auch UCAdressen nennen.
    Der Designer erstellt aber automatisch den Namen UCAdressen1. Ich kann dann aber in UCAdressen umbenennen.
    Darf ich das? Oder gibt es später Probleme, wenn die Instanz auf der Form genauso heißt, wie die UC selbst?

    Und wenn ich in der UC etwas ändere, muss ich das Projekt neu erstellen, die alte UC von der Form löschen und die neue raufziehen.
    Gibts da einen einfachereren Weg?
    Dein UC heißt UCAdressen. Und auf's Form gezogen dann UCAdressen1. Wundert's Dich? Gegenbeispiel Button
    Das MS-Control heißt Button. Und auf's Form gezogen dann Button1. Das ist für Dich doch auch nix besonderes. Wenn die Instanz nur Button heißen würde, gäbe es ab dem 2. Button einen Namenskonflikt.
    Du kannst das Form-eigene UC (fast) nennen, wie Du willst. Du kannst es also auch UCAdressen nennen. Da gibt's keine Konflikte. Mach ich auch.
    Wenn Du auf dem UC was änderst, musst Du die Projektmappe neu kompilieren und dann werden die Änderungen auch auf dem beherbergenden Form gezeigt. Nix mit löschen und neu draufziehen.
    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.
    So ihr lieben. Nun gibt es was, wo sich das drübergucken lohnt.
    Die Adressseite ist soweit fertig - inklusive Emailversand. Ich würde nur noch den Text auf den meisten Buttons durch Bildchen ersetzen - aber das macht es ja für euch eher schwieriger, deswegen spar ichs mir (erstmal).
    Für den Emailversand benötige ich natürlich Emailadressen, welche im DataSet [verschlüsselt] gespeichert werden. Damit ich jetzt nicht zusätzlich eine SettingsPage erstellen muss (und wir 2 Baustellen haben), erzeuge ich im Form Load Dummy Mail Settings.
    Hier kommt es allerdings beim 2. Starten der Anwendung, also nachdem die Daten beim ersten schließen in der xml gespeichert wurden, beim erneuten einlesen der xml zu einer System.Data.ConstraintException: "Einschränkungen konnten nicht aktiviert werden. Mindestens eine Zeile enthält Werte die die Einschränkungen non-null, unique or foreign-key verletzen."
    Ich habe zum ersten mal in meinem Leben bei allen DataRows im Dts die Eigenschaft AllowDBNull auf False gesetzt (um mir das ewige istnull abgefrage zu sparen). Ich vermute hier habe ich aber was versemmelt.
    Oder sollte ich AllowDBNull auf True lassen, wenn ich z.B. möchte das eine Integer Spalte eben auch nichts sein kann?
    Der Rest wie gesagt ist fertig und ich habe mich (bin ich mir zumindest sicher), an die CCD Richtlinien - roter Grad - gehalten.

    Ich bitte um Kritik.

    Edit: Upload aktualisiert und die Verbesserungen von @VaporiZed aus Post 26 und 28 umgesetzt.
    Edit: Upload nach weiteren Verbesserungen in Post 44 verschoben.

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

    Du packst zuerst die DummyDaten ins tDS und lädst danach die tDS-Datendatei. Umdrehen, dann klappt's auch.
    In Deinem FormLoadEventHandler ist aber mit IO.CreateDirectory eine Zeile drin, die kein Methodenaufruf ist.
    Adresse wird im Englischen mit 2xD geschrieben: address.
    Jetzt ist meine Zeit abgelaufen …
    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.
    Jo.
    Den Logikfehler und die Rechtschreibefehler habe ich korrigiert.
    Zur IO.CreateDirectory Zeile habe ich mir gedacht, dass das Auslagen einer einzigen Zeile Code in eine Methode, die ich nur einmal Aufrufe, gegen das KISS Prinzip verstößt.
    Aber wenn dem nicht so ist, änder ich das natürlich.

    Wenn du wieder Zeit hast, wäre es ein Traum, wenn du dich weiter mit dem Code befassen könntest. Ich habe wie gesagt überhaupt keine Eile.

    DerSmurf schrieb:

    Zur IO.CreateDirectory Zeile habe ich mir gedacht, dass das Auslagen einer einzigen Zeile Code in eine Methode, die ich nur einmal Aufrufe, gegen das KISS Prinzip verstößt.

    1. Da widersprichst Du Dir aber selbst: mit LoadDts und SaveDts - das sind jeweils auch Einzeiler.
    2. Die Regeln sind alle nicht widerspruchsfrei. Im Sinne von: Man muss selber eine Gewichtung finden. Das ist auch beim Weißen Grad quasi nachzulesen: Jeder Softwareentwickler soll bei Anwendung der Regeln ein eigenes Maß finden, wie intensiv welche Regel umsetzbar ist.
    3. Ich geh das Ganze tw. noch extremer an: Ich versuche, dass das Form nur noch Aufgaben und Eingaben an andere Klassen delegiert und selbst keine Commands mehr ausführt (außer das Management der anderen Klassen und Eigen-, also GUI-Manipulation). Ist das dann noch KISS? Für manche sicher nicht. But I don't care. Es ist mein Weg, die Regeln umzusetzen.

    Ach ja, Klassiker: Bevor Du weitermachst, bitte die empfohlenen VS-Einstellungen verwenden.
    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.

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

    VaporiZed schrieb:

    . Da widersprichst Du Dir aber selbst: mit LoadDts und SaveDts - das sind jeweils auch Einzeiler.

    Das ist lustig. An diesen beiden Stellen war mir ganz klar, dass ich hierfür eine Methode brauche. Bei der Prüfung auf den Datenordner war mir klar, dass ich das nicht brauche (obwohl das in meiner Welt ja nichtmal ein Einzeiler war). Keine Ahnung, was bei mir falsch läuft :o) Ist jetzt auf jedenfall geändert.

    VaporiZed schrieb:

    bitte die empfohlenen VS-Einstellungen verwenden.

    ups. Habe mir VS2022 installiert und nur daran gedacht den Microsoft VisualBasic Namespace zu entfernen, den Rest hab ich vergessen.
    Mein Projekt ist nun Option Strict On. Hierdurch wurde ein Fehler sichtbar, diesen habe ich korrigiert.

    ErfinderDesRades schrieb:

    ist der Upload denn nu auch updated?

    Jawoll

    Edit: Habe den Upload gerade (10.43 Uhr) nochmal aktualisiert.
    Da das Programm auf unterschiedlich großen Bildschirmen ausgeführt wird, habe ich noch eine Funktion eingebaut, um die Spaltenbreite des Adressen DGV beim Ändern zu speichern und beim Starten zu laden.
    Aber ich höre jetzt wieder auf, damit wir alle den gleichen Stand der Solution haben.

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

    frmMailsenden macht was? Mails vorbereiten und senden. Ist es seine Aufgabe? Fraglich. Vorbereiten ok, aber Mails senden? Darum sollte sich eine eigene Klasse kümmern.
    GetMailData 8| : ByRef solltest Du vermeiden. Wenn Du mehrere Sachen zurückgeben willst, erstell dafür eine Datenklasse, von der Du eine Instanz erstellst und dann zurückgibst. Tupels gingen zwar auch, aber vermeide ich sooft wie möglich, weil ich bei komplexen Datentypen Referenztypen bevorzuge. Da ein Tupel aber ein Wertetyp ist, gibt's unschöne Effekte, wenn man bei einer Tupel-zurückgebenden Funktion Nothing zurückgibt und später die Rückgabe auf Nothing prüfen will.
    Sendmail ist von der Benennung eine Lüge (ich bin da mal bei der Wortwahl radikal). Die Methode sendet keine Mail. Denn wenn die Daten ungültig sind, passiert gar nix. StartSending und SendMail sollten ggf. vom Namen her vertauscht werden. Oder StartMail sollte einen anderen Namen bekommen. In meinen Projekten bevorzuge ich derzeit folgendes Schema:

    VB.NET-Quellcode

    1. Sub PossiblySendMail()
    2. Wenn Vorbedingungen nicht zutreffen, dann Abbruch
    3. SendMail()
    4. End Sub
    5. Sub SendMail()
    6. '…
    7. End Sub

    Damit weiß ich beim lesen von: PossiblyXYZ: Ok, da soll zwar XYZ gemacht werden, aber es könnte aufgrund der Vorbedingungen passieren, dass das nicht gemacht wird. Dementsprechend weiß ich auch: Ok, wenn XYZ nicht gemacht wird, treffen offensichtlich die Vorbedingungen nicht zu und ich kann notfalls da nachschauen, warum nicht. Und da ich die Vorbedingungen gerne in eine Function auslagere, kann ich gezielt nachsehen, wie denn die Vorbedingungen geprüft werden.

    Ob das ein guter Weg für Dich ist, weiß ich nicht. Aber SendMail sollte einen besseren/gezielteren Namen bekommen.

    VB.NET-Quellcode

    1. Private Function TBContainsText(Text As String) As Boolean
    2. If String.IsNullOrEmpty(Text) Then Return False : Return True
    3. End Function

    -> Return Not String.IsNullOrEmpty(Text)

    If (Not (MailAddress.Contains("@"))) Or (Not (MailAddress.Contains(".")))
    Der Unterschied zwischen And und AndAlso/Or und OrElse

    AttachmentDelete -> DeleteAttachments


    So beim schnellen Durchblick.
    Hattest Du Dich schonmal mit Extensions beschäftigt? Die ganzen String.IsNullOrEmpty(Text)-Geschichten würden damit der Vergangenheit angehören, weil Du sie in besser benannten Methoden verstecken kannst. EdR hat ja auch einige in seinen Helpers, die Du ja selber nutzt, Stichwort EditCurrent.
    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.

    VaporiZed schrieb:

    ByRef solltest Du vermeiden

    Magst du mir noch erklären warum?

    VaporiZed schrieb:

    Lüge (ich bin da mal bei der Wortwahl radikal)

    damit kann ich umgehen :) Umbenennungen sind aber noch nicht erfolgt, damit wirds im Folgenden wohl leichter.
    Umbenennen werde ich dann vorm nächsten hochladen,

    Ich habe noch nie eine Klasse in dieser Form erstellt, aber ich habe mich jetzt mal rangemacht:
    Vorab eine Frage:

    VB.NET-Quellcode

    1. Private _bcc as string
    2. Public Property BCC As String'Get
    3. Return _BCC
    4. End Get
    5. Set(ByVal value As String)
    6. _BCC = value
    7. End Set
    8. End Property
    9. 'Public Property BCC as string


    Macht der Auskommentierte Code exakt das gleiche wie der nicht kommentierte?
    Dann wäre es doch immer besser (übersichtlicher) die Kurzschreibweise zu verwenden?

    VB.NET-Quellcode

    1. Private Sub Sendmail()
    2. Dim MailData As New MailEinstellungen(DirectCast(DirectCast(BSEmail.Current, DataRowView).Row, DtsDaten.EmailRow), TBEmpfaenger.Text,
    3. TBBCC.Text, TBCC.Text, TBBetreff.Text, TBNachricht.Text, TBSignatur.Text)
    4. '[...] hier sind noch die Prüfungen ob Emailadressen korrekt und Betreff und Nachricht gefüllt sind
    5. ' diese gehören aber dann auch in die MailEinstellungen Klasse, oder?
    6. StartSending(MailData)
    7. End Sub
    8. Private Sub StartSending(MailData As MailEinstellungen)
    9. Dim Sender = MailData.SenderAddress
    10. Dim Password = MailData.Password
    11. '[...] usw,
    12. End Sub


    und die Klasse:
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Public Class MailEinstellungen
    2. Private _MailSettingsRow As DtsDaten.EmailRow
    3. Private _SenderAddress As String
    4. Private _Password As String
    5. Private _Port As Integer
    6. Private _SMTPServer As String
    7. Private _SSL As Boolean
    8. Private _Recipient As String
    9. Private _BCC As String
    10. Private _CC As String
    11. Private _Subject As String
    12. Private _Message As String
    13. Private _Signature As String
    14. Public Property MailSettingsRow As DtsDaten.EmailRow
    15. Get
    16. Return _MailSettingsRow
    17. End Get
    18. Set(ByVal value As DtsDaten.EmailRow)
    19. _MailSettingsRow = value
    20. End Set
    21. End Property
    22. Public Property SenderAddress As String
    23. Get
    24. Return _SenderAddress
    25. End Get
    26. Set(ByVal value As String)
    27. _SenderAddress = value
    28. End Set
    29. End Property
    30. Public Property Password As String
    31. Get
    32. Return _Password
    33. End Get
    34. Set(ByVal value As String)
    35. _Password = value
    36. End Set
    37. End Property
    38. Public Property Port As Integer
    39. Get
    40. Return _Port
    41. End Get
    42. Set(ByVal value As Integer)
    43. _Port = value
    44. End Set
    45. End Property
    46. Public Property SMTPServer As String
    47. Get
    48. Return _SMTPServer
    49. End Get
    50. Set(ByVal value As String)
    51. _SMTPServer = value
    52. End Set
    53. End Property
    54. Public Property SSL As Boolean
    55. Get
    56. Return _SSL
    57. End Get
    58. Set(ByVal value As Boolean)
    59. _SSL = value
    60. End Set
    61. End Property
    62. Public Property Recipient As String
    63. Get
    64. Return _Recipient
    65. End Get
    66. Set(ByVal value As String)
    67. _Recipient = value
    68. End Set
    69. End Property
    70. Public Property BCC As String
    71. Get
    72. Return _BCC
    73. End Get
    74. Set(ByVal value As String)
    75. _BCC = value
    76. End Set
    77. End Property
    78. Public Property CC As String
    79. Get
    80. Return _CC
    81. End Get
    82. Set(ByVal value As String)
    83. _CC = value
    84. End Set
    85. End Property
    86. Public Property Subject As String
    87. Get
    88. Return _Subject
    89. End Get
    90. Set(ByVal value As String)
    91. _Subject = value
    92. End Set
    93. End Property
    94. Public Property Message As String
    95. Get
    96. Return _Message
    97. End Get
    98. Set(ByVal value As String)
    99. _Message = value
    100. End Set
    101. End Property
    102. Public Property Signature As String
    103. Get
    104. Return _Signature
    105. End Get
    106. Set(ByVal value As String)
    107. _Signature = value
    108. End Set
    109. End Property
    110. Public Sub New(ByVal MailSettingsRow As DtsDaten.EmailRow, Recipient As String, bcc As String, cc As String, Subject As String, Message As String, Signature As String)
    111. _MailSettingsRow = MailSettingsRow
    112. _Recipient = Recipient
    113. _BCC = bcc
    114. _CC = cc
    115. _Subject = Subject
    116. _Message = Message
    117. _Signature = Signature
    118. SenderAddress = _MailSettingsRow.Adresse
    119. Password = _MailSettingsRow.Passwort
    120. Port = _MailSettingsRow.Port
    121. SMTPServer = _MailSettingsRow.SMTPServer
    122. SSL = _MailSettingsRow.SSL
    123. End Sub
    124. End Class


    Edit: Beim erneuten Durchlesen meines Posts fällt mir auf, dass der Name MailEinstellungen für die Klasse wohl ebenfalls unglücklich ist.
    Es sind ja eher MailDaten, oder MailInhalte oder so. Brauchst du also nicht anmeckern, hab ich schon selbst gemacht :)

    Edit2: Beim Mittagessen habe ich bei Youtube über Extensions berieseln lassen. Das Ergebnis sieht so aus:

    VB.NET-Quellcode

    1. Imports System.Runtime.CompilerServices
    2. Module ModExtensions
    3. <Extension()>
    4. Public Function IsntNull(Text As String) As Boolean
    5. return Not String.IsNullOrEmpty(Text)
    6. End Function
    7. End Module

    und der Aufruf dazu:
    If Address.Mail1.IsntNull Then

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

    DerSmurf schrieb:

    VaporiZed-Zitat: ByRef solltest Du vermeiden
    Magst du mir noch erklären warum?
    Weil man Methoden-Parameter verwenden soll, um was in eine Methode reinzustecken, nicht um sie rauszuholen. Wenn Du eine Methodenaufruf PrüfeDatum(Geburtstag) siehst und Geburtstag wird bei Aufruf verändert, weil das ein ByRef-Parameter ist, ist das für den Nutzer von PrüfeDatum sehr verwirrend. Da greift dann PoLA. Eine Methode namens Get… sollte m.E. immer eine Function sein, keine Sub mit ByRef-Parametern.

    Bzgl. Deiner Property: Solange die vollqualifizierte Property nix weiter macht, schlägt VS eh vor, das Ganze in eine AutoProperty umzuwandeln, also in Deinen auskommentierten Einzeiler. Und ja, dann solltest Du die kurze Schreibweise hernehmen. Sobald aber z.B. am Setter was gemacht wird (Setter auf Private setzen, Prüfcode für Value einbauen, das PropertyChangedEvent feuern, …), musst Du es bei der vollen Schreibweise belassen.

    Deine MailWasauchimmer-Klasse ist wofür da? Daten weiterzugeben? Warum schickt die Klasse nicht selber die Mail?

    Extensions: Jou, guter Anfang. Aber die Schreibweise ist falsch. IsntNull? Ach, das soll heißen Text isn't null - ok, das hab ich insofern falsch gelesen, weil ich dachte, dass das Text is not null heißen soll, also IsNotNull. Wenn Dir Deine Schreibweise gefällt, ist's ok. Für andere Leser können Abkürzungen verwirrend sein. Aber es ist Dein Code.
    Ich hab jene Extensions IsEmpty, IsTrimmedEmpty und IsNotEmpty genannt. IsTrimmedEmpty gibt z.B. True zurück, wenn der String leer ist, nur aus Whitespaces besteht oder Nothing ist.
    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.
    Ja. IsEmpty ist wohl verständlicher als Isntnull...
    Sollte ich denn (in der Sub Sendmail) die Prüfungen auf Korrektheit der Emailadresse, und Vorhandensein von Betreff und Nachricht in die Klasse EmailEinstellungen auslagern?
    Dann hätte ich immerhin schonmal den Code etwas getrennt
    Die Form wäre dann zumindest schonmal nicht mehr dazu da die vom User eingegebenen Daten zu validieren.
    Oder sollte die Prüfung der Daten eher zur Eingabe gehören? (also auf dieser Form bleiben)
    Würden die Daten im Form validiert werden, müsste die Form entscheiden, was richtig ist und was nicht. Allerdings hätte es den Vorteil, dass das Form gleich Fehler anzeigen kann.
    Die Datenvalidierung würde ich trotzdem in der Klasse machen und über ein Tupel ( :) ) zurückgeben, ob die Daten ok sind und zusätzlich in einem String die Beschreibung, was ggf. nicht stimmt. Man könnte zwar den Boolean weglassen, denn wenn alles passt, ist der Fehlertext leer, aber ich würd es klar trennen. Das Form ruft dann die Validierungsmethode auf und gibt den evtl. Fehlertext in irgendeiner Art an den User weiter (TextBox, Label, MessageBox, …)
    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.
    SO, ich habe soweit alles umgesetzt.
    Die Benennung der Mailsenden Geschichte ist nun komplett anders.
    Durch den Button Klick auf Email senden wird die Sub ShowMailForm aufgerufen.
    Die geöffnete Form nennt sich nun frmEmailDaten
    Ein Klick auf den dortigen versenden Button ruft ValidateMailData auf und im Anschluss wird die Sub Sendmail aufgerufen.
    (Das finde ich auch beim nochmaligen Niederschreiben hier Sinnvoll - ein gutes Zeichen :) )
    Die Validierung der Daten erfolgt nun in der Mailklasse.
    Außerdem befindet sich die Sendmail Sub nicht mehr innerhalb von frmEmailDaten, sondern in einem eigenen Modul.
    Ein Problemchen habe ich dadurch aber. Auf der frmEmailDaten gibt (oder gab) es eine Progressbar (Marque), die einfach nur anzeigt, dass da was passiert, nachdem eine E-Mail abgeschickt wurde. (Evtl. mit großem Anhang)
    Da ich die Form aber jetzt ja nach dem validieren der Daten nicht mehr brauche - weil ja der Emailversand woanders stattfindet, habe ich auf der MainForm ein StatusStrip erstellt, welches beim Mailversand sichtbar wird.
    Hier gibt es dann wieder eine ProgressBar und ein Label, welches informiert, dass gerade (im HIntergrund) eine Email versendet wird.
    Ob das bei einem erfolgreichen Mailversand funktioniert, habe ich noch nicht getestet (werde ich morgen, mangels fehlender MailCredentials, nachholen).
    Bin noch nicht fit genug mit Async, um mir da sicher sein zu können :)

    Ansonsten gefällt mir auch meine Tupel Lösung sehr gut. Den Code dahinzuschreiben fühlte sich elegant an, fast so, als wüsste ich was ich da tue :)

    Also, ich bitte euch mal wieder darum mir zu sagen, dass mein Code absolut genial ist, oder eben mir aufzuzeigen was (immernoch) schlecht ist.

    Edit: eine angeprangerte Sache habe ich ignoriert. @VaporiZed mangelt den Subnamen AttachmentDelete an, und möchte hier lieber DeleteAttachment sehen.
    Das gilt wohl analog auch mit AttachmentAdd. Ist es aber hier nicht so, dass man auf den ersten Blick sehen sollte, dass da was mit Anhang passiert?
    Ich finde wenn beides untereinandersteht:

    Visual Basic-Quellcode

    1. Private Sub BTN_Click(sender As Object, e As EventArgs) Handles BTNMailversenden.Click, BTNabbrechen.Click, BTNAnhanghinzufuegen.Click, BTNAnhangloeschen.Click
    2. Select Case True
    3. Case sender Is BTNMailversenden : ValidateMailData()
    4. Case sender Is BTNAnhanghinzufuegen : AttachmentAdd()
    5. Case sender Is BTNAnhangloeschen : AttachmentDelete()
    6. End Select
    7. End Sub

    meine Schreibweise deutlich übersichtlicher:

    VB.NET-Quellcode

    1. Case sender Is BTNAnhanghinzufuegen : AttachmentAdd()
    2. Case sender Is BTNAnhangloeschen : AttachmentDelete()
    3. Case sender is BTN1: DeleteAttachment()
    4. Case sender is BTN2: AddAttachment()

    Aber gerne lasse ich mich natürlich auch hier eines besseren belehren.

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

    Hab leider noch keine Zeit, das Projekt anzuschauen, aber bzgl. AttachmentAdd/AddAttachment:
    Was haben folgende Konstrukte gemein:

    VB.NET-Quellcode

    1. BringToFront()
    2. AddAttachment()
    3. CreateDirectory()
    4. BindingSource.RemoveCurrent()
    Sie stellen einen Imperativ dar. Erst Verb, dann Rest. Denn man befiehlt dem Programm, etwas zu tun. Also: »Programm, bring (das Control) nach vorn, häng eine Anlage an, erstelle ein Verzeichnis, entferne das aktuelle BindingSource-Element.« Man redet quasi als Programmierer mit dem Programm. Das ist bei AttachmentAdd nicht gegeben. Aber es ist Dein Code.
    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.

    VaporiZed schrieb:

    Aber es ist Dein Code.

    Aber die Erklärung hat mir gefallen :) Werde ich also umändern (dafür lade ich aber nicht extra neu hoch)

    edit: @VaporiZed die Subnamen in der frmEmailDaten habe ich gerade geändert.
    Mir ist aber aufgefallen, dass ich auf der UCAdressen das gleiche veranstaltet habe. Also falls du drüber stolperst, den Namen der Subs AddressNew, AddressCopy, usw. habe ich auch angepasst.

    edit2: (gelöscht)

    Edit3
    Ich habe meinen zweiten edit Mal entfernt.
    Dieser enthielt eine weitere (neue) Frage.
    Aber lasst uns erstmal alles offene abschließen und dann neue Dinge hinzufügen.

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

    So ihr lieben.
    Nachdem ich angefangen habe mich mit einem Buch zu beschäftigen, habe ich meinen Code überarbeitet.
    Ich bin alle Subs durchgegangen und behaupte nun, dass sämtliche Namen (Subs, Funktionen, Variablen), etc. sinnvoll sind.
    Außerdem habe ich sämtliche Kommentare aus meinem Code entfernt, denn ich behaupte darüber hinaus noch, dass dieser ist nun selbst erklärend und gut (zumindest für meinen Wissensstand) ist.

    Bitte gebt mir mal Rückmeldung, ob ihr das auch so seht, oder ob noch Stellen zu überarbeiten sind.

    Außerdem habe ich noch ein Problem im Code, welches ich nicht selbst behoben bekomme.
    Das Versenden von Email klappt, auch mit der Anzeige und dem Verbergen des StatusStrips. Wenn ich aber zweimal eine Email mit Anhang versende, erhalte ich den Fehler dass auf das verworfene Objekt "System.Net.MailMessage" nicht zugegriffen werden kann.
    Ich führe im SendMail_MailComplete Event ein ​_Mail.Dispose() durch.
    Wenn ich aber eine neue Mail sende, erstelle ich doch ein neues Objekt dieser Klasse. Wo ist hier mein Fehler?

    Falls das jemand mit Code testen muss, und seinde MailCredentials nicht im Kopf hat, gebt mir gerne Bescheid, dann lade ich eine xml mit MailDaten hoch.
    Dateien
    • theo.zip

      (118,63 kB, 16 mal heruntergeladen, zuletzt: )