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.

    bzgl. des Posts des Neuen: Habe ich gelöscht, weil das einfach nur ein kopierter Satz von mir aus Post#158 war. Spam-Verdacht, da sonst kein Zusammenhang zu sehen war ist.
    Ich kann was basteln. Aber letztenendes ist es Filterung des tDS mittels LINQ, nicht mit der FilterStringProperty der BS.
    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:

    Ich kann was basteln. Aber letztenendes ist es Filterung des tDS mittels LINQ, nicht mit der FilterStringProperty der BS.

    Nein da brauchst du nichts basteln, das reicht mir so. Ich denke aber das werde ich an dieser Stelle (noch) nicht machen, da meine Suche ja prinzipiell funktioniert und ich glaube auch nicht so schlecht gelungen ist.
    Ist es nicht so, dass Linq die modernere und wahrscheinlich deutlich flexiblere (und damit für meine Aufgabe hier, die besser geeignete Variante) ist, aber meine Variante auch ihren Zweck (gar nicht so schlecht) erfüllt?

    So. Alles andere habe ich umgesetzt. War jetzt irgendwie leichter als gedacht.
    1. Das Lieferantenproblem habe ich nun so gelöst:

    VB.NET-Quellcode

    1. Private Sub SetSupplier(RowIndex As Integer, ColumnTextBox As TextBox)
    2. Dim ColumnIndex As Integer
    3. Dim SupplierName As String
    4. If Integer.TryParse(ColumnTextBox.Text, ColumnIndex) AndAlso ColumnIndex > 0 Then
    5. If ColumnIndex - 1 <= DGVArtikel.ColumnCount Then
    6. If DGVArtikel.Rows(RowIndex).Cells(ColumnIndex).Value IsNot Nothing Then
    7. SupplierName = DGVArtikel.Rows(RowIndex).Cells(ColumnIndex).Value.ToString
    8. End If
    9. End If
    10. End If
    11. If SupplierName.IsEmpty Then
    12. CCBLieferant.Clear()
    13. Return
    14. Else
    15. CCBLieferant.UndoClear()
    16. End If
    17. Dim dts = DirectCast(BSMain.DataSource, DtsDaten)
    18. Dim SelectedSupplier = dts.Lieferant.FindSupplierByName(SupplierName)
    19. For i = 0 To BSLieferant.Count - 1
    20. If DirectCast(BSLieferant.Item(i), DataRowView).Row Is SelectedSupplier Then BSLieferant.Position = i
    21. Next
    22. End Sub

    Das UndoClear ist nötig, weil ich beim laden der Form ein CCBLieferant.Clear ausführe, damit nichts in der CCBLieferant angezeigt wird, wenn kein Artikel geladen ist (sonst steht ja der erste Lieferant drinne)

    Ich habe zusätzlich beim speichern eines Artikels dann noch eine Prüfung eingebaut:
    If CCBLieferant.IsEmpty Then Return (False, "Lieferant darf nicht leer sein")
    Diese ist beim bearbeiten eines Artikels aber immer True. Ich glaube, weil im Designer die IsEmpty Eigenschaft auf True steht. Aber ich kann das nicht ändern.
    Muss ich hier im Form Load ein CCBLieferant.UndoClear ausführen, oder geht das auch im Designer?

    2. Das ändern / Neuanlegen im Dts (die Lieferanten bearbeiten Geschichte) z.B. im dlgLieferantBearbeiten
    Habe ich umgesetzt, wie von dir vorgeschlagen. Funktioniert natürlich.

    3. Zum Datum:
    Ich übergebe nun z.B. DTPEKend.Value.Date (und die anderen drei Daten genauso).
    In der Suchenklasse siehts nun so aus:

    VB.NET-Quellcode

    1. Public Sub New
    2. '...
    3. If _SearchRetailPriceChanged Then
    4. _RetailPriceChangedStartDate = RetailPriceChangedStartDate.ToString("MM/dd/yyyy HH:mm:ss").Replace(".", "/")
    5. _RetailPriceChangedEndDate = RetailPriceChangedEndDate.ToString("MM/dd/yyyy HH:mm:ss").Replace(".", "/")
    6. End If
    7. ' und beim Verkaufspreis genauso
    8. End Sub
    9. Public Function BuildSearchstring() As String
    10. '...
    11. If _SearchRetailPriceChanged Then
    12. If Searchstring = "" Then
    13. Searchstring = $"DatumletzteKalkulationVK > #{_RetailPriceChangedStartDate}# AND DatumletzteKalkulationVK < #{_RetailPriceChangedEndDate}#"
    14. Else
    15. Searchstring = "(" & Searchstring & $") AND DatumletzteKalkulationVK > #{_RetailPriceChangedStartDate}# AND DatumletzteKalkulationVK < #{_RetailPriceChangedEndDate}#"
    16. End If
    17. End If
    18. return searchstring
    19. End Function

    Aber ich glaube (wenn ich hier nicht wieder einen Denkfehler habe), dass ich das "=" trotzdem brauche.
    Denn wenn ich am 05.08.2022 den VK eines Artikels geändert habe, dann stelle ich bei Startdate 05.08.2022 und bei EndDate auch 05.08.2022 ein.
    Ohne "=" würde nichts gefunden werden - ich müsste vom 04.08 bis 06.08. suchen.

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

    zu 1.: mal schauen …
    zu 2.:

    DerSmurf schrieb:

    Funktioniert natürlich.
    danke, aber das ist nicht immer erwartbar. Selbst ich gehe schon lange davon aus, dass das, was ich mache, nicht funktioniert. Aus Erfahrung :rolleyes:
    zu 3.: Mach, wie es klappt. Die Details Deines Programms kenne ich nicht. Wenn das = gebraucht wird, nutze es.
    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. Dann teste ich morgen Mal mit dem =.
    Ich muss ja aber eh noch schauen, ob DatumLetzteKalkulationVK, also das Datum im DTS eine Uhrzeit hat. (Das hatte ich vergessen)
    Falls ja, muss ich ja hier auch "um Mitternacht" speichern.
    Dann könnte es auch ohne Gleichheitszeichen gehen. Vielleicht. Mal gucken. Ich war so froh, dass der doofe Datumsvergleich funktioniert hat xD

    Heißt dein "Mal schauen", dass du später nochmal rüber schaust?
    jou. Heute nicht mehr. Es wird Feierabendzeit 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.

    DerSmurf schrieb:

    Ist es nicht so, dass Linq die modernere und wahrscheinlich deutlich flexiblere (und damit für meine Aufgabe hier, die besser geeignete Variante) ist, aber meine Variante auch ihren Zweck (gar nicht so schlecht) erfüllt?
    Kann man so nix zu sagen.
    "Min Linq" kann auf zig verschiedene Weisen umgesetzt werden.
    Es gibt auch LinqToDataset, speziell für Dataset - dazu habich auch ein Tut gemacht.
    Das kann paar Dinge, die BindingSource.Filter nicht kann. Viele andere Dinge, die man eiglich erwarten würde, kanns aber auch nicht.
    Und wenn man mit LinqToDataset filtert, und will dann mit SpaltenHeader-Klick sortieren - dann ist der Filter wieder kaputt.
    Also LinqToDataset fand ich buggy, und nur für spezielle aufgaben eine Option.

    Ich glaube aber, VPZ meint mit "Filterung des tDS mittels LINQ" was anderes - nicht LinqToDataset. Ich kann mir allerdings nur vorstellen, dass er auf List(Of DataRow) wechselt, und damit ist möglicherwweise die ÄnderungsVerfolgung im Eimer - und mir unklar ist, ob man dann so einem Filtrat noch was zufügen/löschen kann.

    Also ich bin konservativ, und ziehe vorsorglich erstmal in Zweifel, ob Linq im tds eine modernere, flexiblere, bessere Alternative ist zu olle BindingSource.Filter.

    ErfinderDesRades schrieb:

    Ich glaube aber, VPZ meint mit "Filterung des tDS mittels LINQ" was anderes - nicht LinqToDataset

    Er wird es uns sicher mitteilen :o)
    Aber es scheint ja festzustehen, dass es sich eher um Geschmackssache, als um besser/schlechter (also BS.Filter und Linq), handelt.

    Ich habe aber noch drei zwei Fragen zum Projekt.
    1. Die Frage mit meiner CCB in auf der frmArtikelBearbeiten (Siehe Vorpost - Frage Nummer1)

    2. (keine Frage merke ich gerade - nur eine Anmerkung) Das Datum. Ich habe mir überlegt, dass ich einen anderen Ansatz wähle. Da es aktuell ja reichlich "Preisanpassungen" gibt, kontrolliere ich an machen Tagen 2 mal täglich meine Rechnungen. Einmal morgens und dann nochmal Nachmittags.
    Wenn ich nun heute morgen und heute Nachmittag Verkaufspreise ändere und den "VK geändert" Filter auf Heute stelle, finde ich alle Artikel deren VK heute geändert wurden.
    Hier wäre es manchmal hilfreich, wenn ich eben Nachmittags, die Artikel von morgens nicht sehe.
    Also habe ich mich entschieden die Uhrzeit im Filter mit anzugeben. Die DTP zur Auswahl habe ich auf Format Custom mit "dd.MM.yy - HH:mm" eingestell und übergebe an meine Suchenklasse wieder das vollständige Datum (mit Uhrzeit).
    Beim ändern eines Artikelpreises wird die Uhrzeit mit gespeichert.
    Es funktioniert alles:

    VB.NET-Quellcode

    1. If _SearchPurchasingPriceChanged Then
    2. If Searchstring = "" Then
    3. Searchstring = $"DatumletzteKalkulationEK >= #{_PurchasingPriceChangedStartDate}# AND DatumletzteKalkulationEK <= #{_PurchasingPriceChangedEndDate}#"
    4. Else
    5. Searchstring = "(" & Searchstring & $") AND DatumletzteKalkulationEK >= #{_PurchasingPriceChangedStartDate}# AND DatumletzteKalkulationEK <= #{_PurchasingPriceChangedEndDate}#"
    6. End If
    7. End If

    Und die eine Zeile zum ändern des EndDatums - PurchasingPriceChangedEndDate = PurchasingPriceChangedEndDate.Date.AddDays(1).AddMinutes(-1) habe ich entfernt. Die brauch ich ja nicht mehr.

    3. In den Projekteigenschaften ist als Startform die Form1 ausgewählt. Diese gibt es nicht mehr, da ich sie in frmHaupt umbenannt habe.
    Aber in der Combobox kann ich keine andere Startform auswählen?

    Und ich lade die aktuelle Solution nochmal hoch, die aus dem Vorpost hatte ja eh noch keinen Download.
    Dateien
    • Theo.zip

      (2,25 MB, 7 mal heruntergeladen, zuletzt: )
    Zu Punkt 3: In der Datei My Project\Application.Designer.vb gibt es den Teil, die Du ändern musst:

    VB.NET-Quellcode

    1. <Global.System.Diagnostics.DebuggerStepThroughAttribute()> _
    2. Protected Overrides Sub OnCreateMainForm()
    3. Me.MainForm = Global.Theo.frmHaupt
    4. End Sub


    ##########

    Zu 1: Die CCB ist (noch) nicht dafür gedacht, einen Vorabwert zu haben. Sie hat ja die Aufgabe, Dich zu einer Auswahl zu zwingen. Daher ist von Haus aus das IsEmpty noch True. Aber Du verwendest sie ja hier bei der ArtikelBEARBEITUNG als normale ComboBox. Mir ist klar, dass Du Dir einen Dialog einsparen willst, indem Du Neuanlage und Bearbeitung mit einem Form machst. Aber das ist so nicht in meinen Sinn gewesen. Wenn das Ziel mit dem UndoClear erreichbar ist, ok. Ansonsten musst Du Dich an der CCB-Codequelle zu schaffen machen. Ist ja OpenSource.
    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“ ()

    Zu 3. Nein, das hilft leider nicht, weil habe ich schon gemacht.
    Bei mir siehts aus wie in deinem Post:

    VB.NET-Quellcode

    1. <Global.System.Diagnostics.DebuggerStepThroughAttribute()> _
    2. Protected Overrides Sub OnCreateMainForm()
    3. Me.MainForm = Global.Theo.frmHaupt
    4. End Sub

    Aber in My Project --> Anwendung kann ich nichts auswählen, als Form1.


    Zu 3. Ich habs nun etwas anders gelöst. Wenn ich im FormLoad Event der Artikelform meine LoadArticleData Sub aufrufe, funktioniert CCBLieferant.UndoClear nicht, weil in der dann ausgeführten Sub "DataSource" nothing ist und diese verlassen wird.
    Ich habe also eine Public Sub innerhalb der CCBKlasse erstellt: SetMeNotEmpty
    und rufe nun folgendes auf:

    VB.NET-Quellcode

    1. CCBLieferant.SetMeNotEmpty()
    2. CCBLieferant.Text = .LieferantRow.Name

    Warum ich an dieser Stelle direkt in die CCB schreiben kann und letztens nicht, verstehe ich nicht ganz, aber es klappt.
    Ist wohl nicht ideal deine CCB "normal" - also mit ISEmpty = True - aufzurufen und diesen Wert dann wieder auf False zu setzen, aber mir fallen viele Stellen ein, wo ich deine CCB "im gedachten" Sinne verwende und nur diese eine hier wos anders ist, deswegen hoffe ich mal, das geht so in Ordnung.

    Aber zwei Fragen habe ich noch (hab ich bisher immer vergessen):
    2. In deiner CCB taucht die Variable DataSource (ohne _) auf. Wo kommt die her? Ich finde keine Deklaration.
    3. Wenn ich innerhalb einer UC auf Code im DataSet zugreifen möchte (z.B. in der UCArtikel Zeile 93 ff) kann ich nicht:
    If Not DtsDaten.Artikel.ArtNrExistsWithinASupplier(NewArtNr, SelectedSupplier) Then ausführen.
    Ich erhalte dann den Fehler: "Der Verweis auf einen nicht freigegebenen MEmber erfordert einen Objeltverweis.
    Da ich mir nicht anders zu helfen wusste habe ich hieraus folgendes gemacht:

    VB.NET-Quellcode

    1. Dim dts = DirectCast(BSMain.DataSource, DtsDaten)
    2. If Not dts.Artikel.ArtNrExistsWithinASupplier(NewArtNr, SelectedSupplier) Then

    Aber geht das nicht auch einfacher?
    Habe VS 2022 17.3.0 Preview 6.0, habe Dein Projekt aus Post#168 runtergeladen, da klappt das problemlos mit der Startformeinstellung, siehe Anhang.

    DerSmurf schrieb:

    In deiner CCB taucht die Variable DataSource (ohne _) auf. Wo kommt die her? Ich finde keine Deklaration.
    Aus der Basisklasse, da die CCB eine ComboBox ist: Public Class ClearableComboBox : Inherits ComboBox

    Bzgl UC und tDS: Du hast auf Deinen UCs keine tDS-Instanz, sondern stattdessen die BSMain, also ist der von Dir eingeschlagene Weg genau der richtige.

    Die BSMain ist ja dafür da, damit Du nicht alle vom tDS abhängigen BindingSources umstöpseln musst, also deren DataSource neu setzen musst, wenn Du das Form aufrufst, sondern eben nur die DataSource der BSMain. Ich selbst arbeite ja schon lange nicht mehr mit tDS, habe aber auf jedem Form folgende Herangehensweise:
    • eine DataContainer-Instanz, die alle Daten beinhaltet, analog zum tDS
    • eine DataContainer-BS auf dem Form, an die andere BindingSources koppeln; im FormX.Designer.vb stell ich deren DataSource auf GetType(DataContainer), damit der Designer bescheid weiß und die anderen BindingSources an die Bestandteile des DataContainers koppeln können und Controls dann richtig eingestellt werden können
    • bei SubForm-Instanziierung übergebe ich die DataContainer-Instanz und führe im Startcode des SubForms eben die Umstöpselung der DataContainer-BS-DataSource auf die DataContainer-Instanz durch
    • im Code kann ich direkt auf die DataContainer-Instanz zugreifen und die Daten manipulieren
    Bilder
    • Projekteinstellungen.png

      36,41 kB, 816×619, 7 mal angesehen
    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 2 mal editiert, zuletzt von „VaporiZed“ ()

    Neu

    @VaporiZed
    Du hattest vollkommen Recht. @ErfinderDesRades und ich liegen falsch.
    Seine Aussage war ganz klar, immer Item. Article verwendet im englischen niemand, wenn er über einen Artikel spricht.

    Ich habe jetzt einen haufen Umbennenungen vor mir :o)

    Aber ich habe auch noch zwei Fragen.
    1. Die Artikelsuche:
    Ich würde gerne zusätzlich noch eine Filterung nach Kategorie hinzufügen. Also genauso wie mit den Lieferanten.
    Aber ich kann ja nicht noch eine Bindingsource an die Suche klatschen. Dann könnte ich ja immer nur entweder nach Lieferant, oder nach Kategorie filtern.
    Gibt es hier einen Filterstring, mit dem ich den Verweis des Artikels auf die Kategorie Table durchsuchen kann?
    Oder ist mein BindingSource.Filter hier am Ende? Alternativ könnte ich ja dann noch eine "berechnete Spalte" in den Artikeln hinzufügen, welche einen Verweis auf den Namen der Kategorie enthält.
    Danach könnte ich ja dann ganz normal filtern. Aber nur dafür eine Spalte im Dts?

    2. (was neues) - ich habe auf der frmHaupt eine Drag and Drop Funktion eingebaut. Der User schmeißt eine Datei auf die Form, wählt aus um welche Art es sich handelt (Rechnung, Bestellung, Preisliste, ...) und die Datei wird am entsprechenden Ordner abgelegt.
    Dies habe ich für den Fall einer Preisliste, Stockliste und eines Angebotes ausprogrammiert. Wenn es sich bei der DragDrop Datei um eine pdf, oder txt handelt, wird diese im WebView2 angezeigt.
    Die Datei landet im Ordner /Daten/ArtderListe/Firmaname, inkl. Prüfung ob es die Datei schon gibt.
    Könntest du hier mal über "die Struktur" des Codes schauen? Ist das so OK?

    Hier der Code - Solution hängt auch dran, aber ich habe das WebView2 runtergeladen (und muss es natürlich anhängen), das macht es recht groß. Wenn das jemanden stört, bitte bescheid sagen, dann nehme ich es vor dem Upload raus.
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Private Sub frmHaupt_DragEnter(sender As System.Object, e As System.Windows.Forms.DragEventArgs) Handles Me.DragEnter
    2. If e.Data.GetDataPresent(DataFormats.FileDrop) Then
    3. e.Effect = DragDropEffects.Copy
    4. End If
    5. End Sub
    6. Private Sub frmHaupt_DragDrop(sender As System.Object, e As System.Windows.Forms.DragEventArgs) Handles Me.DragDrop
    7. Dim droppedFiles() As String = CType(e.Data.GetData(DataFormats.FileDrop), String())
    8. processFiles(droppedFiles)
    9. End Sub
    10. Public Sub processFiles(droppedFiles() As String)
    11. For Each File In droppedFiles
    12. Dim DroppedFileInfo As FileInfo = New FileInfo(File)
    13. Dim NewFileName As String
    14. Dim DeleteOriginalFile As Boolean
    15. Using ChooseFileType As New dlgDateiTypAuswahl
    16. dlgDateiTypAuswahl.LBLDateiname.Text = Path.GetFileNameWithoutExtension(DroppedFileInfo.Name)
    17. ChooseFileType._Fileinfo = DroppedFileInfo
    18. If My.Settings.frmDateiAuswahlPosition.IsEmpty Then
    19. ChooseFileType.Size = New System.Drawing.Size(1049, 579)
    20. Else
    21. ChooseFileType.Size = My.Settings.frmDateiAuswahlSize
    22. ChooseFileType.Location = My.Settings.frmDateiAuswahlPosition
    23. End If
    24. If ChooseFileType.ShowDialog() = DialogResult.OK Then
    25. DeleteOriginalFile = ChooseFileType._DeleteOriginalFile
    26. Select Case ChooseFileType._FileType
    27. Case = dlgDateiTypAuswahl.FileType.Invoice : MessageBox.Show("Rechnung")
    28. Case = dlgDateiTypAuswahl.FileType.Order : MessageBox.Show("Bestellung")
    29. Case = dlgDateiTypAuswahl.FileType.Reclamation : MessageBox.Show("Reklamation")
    30. Case = dlgDateiTypAuswahl.FileType.Costs : MessageBox.Show("Kosten")
    31. Case = dlgDateiTypAuswahl.FileType.Offer
    32. NewFileName = ChooseFileType._NewFileName
    33. ListDropped(DroppedFileInfo, NewFileName, My.Application.Info.DirectoryPath & "\Daten\Angebote\", "Angebot", DeleteOriginalFile)
    34. Case = dlgDateiTypAuswahl.FileType.StockList
    35. NewFileName = ChooseFileType._NewFileName
    36. ListDropped(DroppedFileInfo, NewFileName, My.Application.Info.DirectoryPath & "\Daten\Stocklisten\", "Stockliste", DeleteOriginalFile)
    37. Case = dlgDateiTypAuswahl.FileType.PriceList
    38. NewFileName = ChooseFileType._NewFileName
    39. ListDropped(DroppedFileInfo, NewFileName, My.Application.Info.DirectoryPath & "\Daten\Preislisten\", "Preisliste", DeleteOriginalFile)
    40. Case = dlgDateiTypAuswahl.FileType.Open : MessageBox.Show("öffnen")
    41. Case = dlgDateiTypAuswahl.FileType.Skip : MessageBox.Show("überspringen")
    42. End Select
    43. End If
    44. End Using
    45. Next
    46. End Sub
    47. Private Sub ListDropped(DroppedFileInfo As FileInfo, NewFileName As String, CopyPath As String, ListType As String, DeleteOriginalFile As Boolean)
    48. Dim SupplierName = SelectSupplierByName()
    49. If SupplierName.IsEmpty Then Return
    50. Dim TargetPath = New DirectoryInfo(CopyPath & SupplierName)
    51. Directory.CreateDirectory(TargetPath.FullName)
    52. Dim NewFullFilePath = $"{TargetPath.FullName}\{NewFileName}"
    53. Do While File.Exists(NewFullFilePath)
    54. If Not ShowMessageBoxAndAskUserYesOrNo($"Die Datei {NewFileName} existiert bereits.{Environment.NewLine}Wollen Sie {NewFileName} umbennen?") Then Exit Do
    55. NewFileName = SetNewFilename(NewFileName, DroppedFileInfo.Extension)
    56. NewFullFilePath = $"{TargetPath.FullName}\{NewFileName}"
    57. Loop
    58. DroppedFileInfo.CopyTo(NewFullFilePath, True)
    59. ShowAutoClosingMessageBox($"{SupplierName} {ListType} - {NewFileName} gespeichert")
    60. If DeleteOriginalFile Then DroppedFileInfo.Delete()
    61. End Sub
    62. Private Function SetNewFilename(OldFileName As String, Extension As String) As String
    63. Dim NewFilename As String
    64. Using NewFileNameForm As New dlgneuerDateiname
    65. With NewFileNameForm
    66. ._OldFileName = OldFileName
    67. ._Extension = Extension
    68. If .ShowDialog(Me) = DialogResult.OK Then
    69. NewFilename = ._NewFileName
    70. End If
    71. End With
    72. End Using
    73. Return NewFilename
    74. End Function
    75. Public Function SelectSupplierByName() As String
    76. Dim Name As String
    77. Using SupplierSelect As New dlgLieferantenAuswahl
    78. SupplierSelect.BSMain.DataSource = DtsDaten
    79. If SupplierSelect.ShowDialog = DialogResult.OK Then
    80. Name = SupplierSelect.SupplierName
    81. End If
    82. Return Name
    83. End Using
    84. End Function

    CodeTags korrigiert ~VaporiZed
    Dateien
    • Theo.zip

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

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

    Neu

    Hmm. Dann konkretiesier ich meine Frage mal.
    Gehört die Sub processDroppedFiles und alle Subs die dann damit zusammen gehören, in eine (normale) Klasse, in eine Shared Klasse, oder in ein ganz normales Modul?
    Da bin ich mir gerade irgendwie nicht einig mit mir selber.
    Also im Prinzip wählt der User eine (oder mehrere) Dateien aus (oder Droppt sie auf die Form) und wählt dann, mithilfe einer Form, um welche Art von Datei es sich handelt( (Rechnung, Bestellung, Preisliste, etc.), damit diese dann innerhalb der Ordnerstruktur an den richtigen Platz abgelegt wird.
    Darüber hinaus passieren noch Dinge, wie Form für Emailversand öffnen, wenn es sich um eine Reklamation handelt.

    Und noch eine Frage: vermutlich an @ErfinderDesRades
    Kann ich irgendwie nachvollziehen, ob mittels EditNew ein neuer Eintrage angelegt wurde (oder ob der User den Dialog mit Cancel verlassen hat)
    BSReklamation.EditNew(Of dlgReklamationBearbeiten)(tpls)

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

    Neu

    Aufgrund der vielen Interaktionen mit User und Form würd ich es dort belassen. Eine Klasse wird bei mir dann erschaffen, wenn sie unabhängig von User und Form auskommt. Damit mein ich nicht, dass Daten von den beiden nicht kommen dürfen, sondern nur, dass sie bei Klassen-Funktionsaufruf feststehen. Auch MessageBoxen gibt's bei keiner meiner projektinternen Datenverarbeitungsklassen. Es gibt eine Ausnahme, nämlich in einer DLL, bei der bei Projektende oder zu einem gewünschten Zeitpunkt gefragt wird, ob Daten gespeichert werden sollen und an die Datenpersistierung übergeben werden sollen. Dabei hat der (versierte) User auch die Möglichkeit, die Änderungen anzuschauen. Aber davon abgesehen halte ich die Klassen userentscheidungsfrei.
    Auch holst Du Daten aus den Settings und manipulierst Dialoge. Das sind weitere Gründe für mich, die Funktionen da zu belassen, wo sie sind. Es gibt für mich einen recht einfachen Trick, da Abhängigkeiten aufzuzeigen: Verschieb die Methoden in Deine neue Wunschklasse in einer eigenen Datei und kopier die Klassendatei in ein Konsolenprojekt rein. Wenn da ganz viele Alarme losgehen, dass da einiges nicht mehr kompilierbar ist, erkennst Du die Abhängigkeiten, die v.a. Form- und Settings-spezifisch sind.

    Die Designfrage hat mich auch schon beim DataTable-Debuggen beschäftigt. Da hab ich mich n bissl fusselig gesucht, bis ich das mit dem Collapsed gefunden hatte. Im Designer sollte - eben zum Designen - alles da und sichtbar sein und erst zur Laufzeit ausgeblendet/umgeformt werden.
    Ah, jetzt weiß ich auch, warum das Designbild nicht angezeigt wurde. Du hast es gelöscht und die Frage entfernt.
    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.

    Neu

    Ja, habe meinen Edit gelöscht. In der Hoffnung, dass es noch niemand gesehen hat.
    Habe mein Problem durch ein paar beherzte Versuche gelöst. Scheinbar war nur mein Designer ein bisschen zickig.

    VaporiZed schrieb:

    . Da hab ich mich n bissl fusselig gesucht, bis ich das mit dem Collapsed gefunden hatte.

    Das leuchtet mir ein, ändere ich ab.
    Meinen restlichen Code mache ich dann erstmal fertig (in der frmHaupt). Dann sehen wir weiter. Ich finde das nämlich recht viel Code - jetzt wo es dem Ende hingeht.
    Aber da reden wir drüber, wenns fertig ist.

    Ein aktuelles Problem habe ich aber noch. Edit: Problem gelöst.
    Auf meiner UCArtikel (nicht in der heir hochgeladenen Solution), gibt es einen SplitContainer mit Panel2.collapsed = True im Designer (ändere ich wie gesagt noch ab).
    Dieses Panel wird bei Bedarf angezeigt. Der User soll aber die Größe (also die Höhe) festlegen können.
    Dazu speichere ich die SplitterDistance (SCArtike ist der Name des SplitContainers): My.Settings.SCArtikelSplitterDistance = Me.SCArtikel.SplitterDistance
    Das Anzeigen dieses Panels sieht so aus:

    VB.NET-Quellcode

    1. Private Sub ShowFileInWebView(DroppedFileInfo As FileInfo)
    2. If PossibleToShowFileInWebView(DroppedFileInfo) Then
    3. With UcArtikel
    4. .WebView2.Source = New Uri(DroppedFileInfo.FullName)
    5. .SCArtikel.SplitterDistance = My.Settings.SCArtikelSplitterDistance
    6. .SCArtikel.Panel2Collapsed = False
    7. ShowArticlePage()
    8. End With
    9. Else
    10. ShowAutoClosingMessageBox("Die Datei kann nicht angezeigt werden.")
    11. End If
    12. End Sub

    Allerdings ist die dann angezeigte SplitterDistance immer kleiner (also das Panel2 größer) als gespeichert.
    Was läuft hier falsch?

    Edit: DIe aktuelle Solution kommt gleich. Ich ändere nur noch eben die SplitContainer, damit im Designer alles sichtbar ist.
    Sonst hast du zu tun xD

    und das letzte Edit für heute.
    Ich habe nun im Designer Panel2collapsed auf False und setze es im FormLoad Event auf True.
    Dann habe ich die Sub ​StartSpecialSubForVaporized erstellt, welche nur das Panel anzeigt und ausblendet, damit du nicht irgendwelche pdfs auf die Form ziehen musst.
    Aber seid der "Umlagerung" von Panel2Collapsed ins Form Load, wird mir die korrekte Höhe angezeigt.
    Also alles schick.

    Also formulier ich mein Drag and Drop Gedöns mal zu ende. Dann lohnt sich das drüber gucken wieder.
    Aber erstmal hast du ein paar Tage Ruhe vor mir. Der Versuch das ganze ordentlich" zu machen, nimmt ganz schön Zeit in Anspruch (das meine ich positiv).

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

    Neu

    DerSmurf schrieb:

    Allerdings ist die dann angezeigte SplitterDistance immer kleiner (also das Panel2 größer) als gespeichert.

    Hast du im EventHandler mitgeteilt, dass der neue Wert in den My.Settings gespeichert werden soll?

    VB.NET-Quellcode

    1. Private Sub SCArtikel_SplitterMoved(sender As Object, e As SplitterEventArgs) Handles SCArtikel.SplitterMoved
    2. My.Settings.SCArtikelSplitterDistance = SCArtikel.SplitterDistance
    3. End Sub


    Muss ja gespeichert werden beim Verändern (oder beim Verlassen der Form: bei mir speicher ich das inne Datenbank, deshalb immer erst beim schließen der Form - sind sonst zuviele Updates...), sonst wird natürlich der Wert aus dem Designer jedesmal geladen
    "Na, wie ist das Wetter bei dir?"
    "Caps Lock."
    "Hä?"
    "Shift ohne Ende!" :thumbsup:

    Neu

    @tragl Danke fürs einmischen und SORRY! Das Problem hat sich von selbst gelöst. Durch das ausblenden des Panels zur Laufzeit statt im Designer, tritt das Problem nicht mehr auf.

    Aber eine Sache ist untergegangen: (Betrifft UploadAnwendung aus Post 171 - seid dem habe ich nichts mehr an der Suche geändert)

    DerSmurf schrieb:

    1. Die Artikelsuche:
    Ich würde gerne zusätzlich noch eine Filterung nach Kategorie hinzufügen. Also genauso wie mit den Lieferanten.
    Aber ich kann ja nicht noch eine Bindingsource an die Suche klatschen. Dann könnte ich ja immer nur entweder nach Lieferant, oder nach Kategorie filtern.
    Gibt es hier einen Filterstring, mit dem ich den Verweis des Artikels auf die Kategorie Table durchsuchen kann?
    Oder ist mein BindingSource.Filter hier am Ende? Alternativ könnte ich ja dann noch eine "berechnete Spalte" in den Artikeln hinzufügen, welche einen Verweis auf den Namen der Kategorie enthält.
    Danach könnte ich ja dann ganz normal filtern. Aber nur dafür eine Spalte im Dts?

    Hier habe ich aber ja die berechnete Spalte EXPLieferant, welche einfach nur den Namen des Lieferanten enthält.
    Das könnte ich ja mittels BS.Filter EXPName = CBLieferant.text (oder so in der Art) filtern. Und meine BSArtikelFiltered stöpsel ich dann um, auf die Kategorie.
    Oder geht das einfach eleganter?

    Und @VaporiZed Sorry für die falschen CodeTags in Post 171. Fällt mir jetzt erst auf, dass du da korrigier Bedarf hattest.

    Edit: @VaporiZed Push :)

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