Hilfe beim Umbau eines Programmes

  • VB.NET
  • .NET (FX) 4.5–4.8

Es gibt 57 Antworten in diesem Thema. Der letzte Beitrag () ist von Amelie.

    Hilfe beim Umbau eines Programmes

    Hallo zusammen. :)

    Hilfe benötigt. :rolleyes:
    Ich bin ja dabei das Programm für die "Wetterdaten" meines Opas umzubauen / neu aufzubauen größtenteils als Übung für mich selber.
    Hierzu habe ich nun mal ein neues Konzept geschrieben.

    Gleich noch zur Info: Seit quasi eintag Tag arbeite ich nun mit VS2015. 2019 läuft nicht gut auf meinem PC!
    Spoiler anzeigen

    XML-Quellcode

    1. Aufgabenstellung: Wetterdatenverwaltung mit VB.netEntwickel ein VB.net-Programm zur Verwaltung von Wetterdaten. Das Programm soll es dem Benutzer ermöglichen, Wetterdaten manuell einzugeben, zu speichern und verschiedene Berechnungen wie Monats- und Jahresdurchschnitte durchzuführen.
    2. Das Programm sollte die folgenden Funktionen enthalten:
    3. Eingabe von Wetterdaten:Der Benutzer sollte in der Lage sein, Wetterdaten wie Temperatur, Luftfeuchtigkeit, Niederschlagsmenge usw. für beliebige Tage einzugeben.
    4. Datenspeicherung:Das Programm sollte die eingegebenen Wetterdaten in einer geeigneten Datenstruktur speichern, z. B. DataTable oder einer XMLDatei.Es müssen Dateien für jedem Monat eines Jahres in Verzeichnissen abgelegt werden.Beispiel: Wetterdaten\Jahr\Monatsdateien
    5. Datenverwaltung:Der Benutzer sollte in der Lage sein, gespeicherte Wetterdaten anzuzeigen, zu bearbeiten und zu löschen. Es sollte eine übersichtliche Benutzeroberfläche geben, um durch die Daten zu navigieren.
    6. Berechnungen:Das Programm sollte Funktionen zur Berechnung von Monats- und Jahresdurchschnitten der Wetterdaten bereitstellen. Der Benutzer sollte in der Lage sein, einen bestimmten Zeitraum auszuwählen und das Programm sollte den entsprechenden Durchschnitt berechnen.
    7. Datenvisualisierung:Das Programm sollte Diagramme oder Grafiken generieren, um die Wetterdaten visuell darzustellen. Dies könnte beispielsweise in Form von Linien- oder Balkendiagrammen erfolgen.
    8. Benutzerfreundlichkeit:Das Programm sollte eine benutzerfreundliche Oberfläche haben, die eine einfache Bedienung ermöglicht. Es sollte klare Anweisungen geben und Fehlermeldungen anzeigen, falls der Benutzer ungültige Daten eingibt.
    9. Datensicherung:Der Benutzer soll in der Lage sein, die angefallenen Daten in einem BackUp zu sichern und wieder Restaurieren zu können.
    10. Zusätzliche Funktionen hinzufügen, um das Programm zu erweitern, falls gewünscht.



    Ich habe die erste Version rein mit XML Dateien gemacht. Dabei versucht mich an OOP zu halten. Die Version funktioniert und mein Opa arbeitet schon damit.
    Das bedeutet aber auch, das ich mich an die erzeugten "XML-Dateien" beim Umbau/Neugestaltung halten muss. Hierzu habe ich mir auch schon ein kleines Hilfsprogrmm geschrieben um die Daten ggf umzustellen.
    Beispiel: <RegenTag>6/RegenTag> gegen <RegenTag>6,0</RegenTag>


    Die erste Version der WetterApp ist aber noch sehr umständlich, das es quasie aus 3 einzenlen Programmen besteht. Dateneingabe, Jahresdaten / Durchschnitte und BackUp

    Die zweite Version habe ich dann mit DataTable DataSet und Bingings angefangen, auch dabei versucht OOP zu beachten usw. Das eingeben der Daten und das automatische erzeugen von neuen Monaten und speichern etc klappt auch.

    Nun bin ich an einem Punkt angekommen, wo ich mich immer mehr "verzettele". Soll bedeuten, mein Code wird wieder unstrukturiert usw...
    Mir fehlt einfach die Erfahrung, wann ich wofür Klassen bauen muss usw..
    Ich hänge mal das bereinigte Project an damit ihr seht was ich so gemacht habe.

    Der Ausdruck: so sollen die Daten im DGV und im Ausdruck aussehen. Also das mit der Nachkomma-Null z.B.: 12.0
    Bilder
    • pfAusdruck.jpg

      240,73 kB, 1.190×271, 176 mal angesehen
    • wetterstation.jpg

      320,58 kB, 800×433, 176 mal angesehen
    Dateien
    • Wetterstation.zip

      (168,46 kB, 233 mal heruntergeladen, zuletzt: )
    Asperger Autistin. Brauche immer etwas um gewisse Sachen zu verstehen. :huh:
    ich hab mal den clsXmlManager und clsDateManager rausgeworfen, und stattdessen die Load/Save-Business-Logik im typDataset angelegt.

    VB.NET-Quellcode

    1. Partial Class dsWeather
    2. Public _filePathsConfig As New FilePathsConfig
    3. Public Sub LoadXMLData()
    4. Clear()
    5. If File.Exists(_filePathsConfig.XMLFileName) Then
    6. Me.ReadXml(_filePathsConfig.XMLFileName)
    7. Else
    8. GenerateMonth()
    9. End If
    10. Me.AcceptChanges()
    11. End Sub
    12. Private Sub GenerateMonth()
    13. Dim dt = _filePathsConfig._dtpDatum.Value
    14. Dim daysInMonth As Integer = DateTime.DaysInMonth(dt.Year, dt.Month)
    15. For day As Integer = 1 To daysInMonth
    16. Dim sDay = day.ToString("00") & "-" & Path.GetFileNameWithoutExtension(_filePathsConfig.XMLFileName)
    17. Me.WeatherData.AddWeatherDataRow(sDay, "", "", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
    18. Next
    19. ' MessageBox.Show("Die Monatsdatei wurde erfolgreich angelegt." & Environment.NewLine & "Datei: " & _filePathsConfig.XMLFileName, "XML-Datei-Erfolg", MessageBoxButtons.OK, MessageBoxIcon.Information)
    20. End Sub
    21. Public Sub SaveXMLData()
    22. Me.WriteXml(_filePathsConfig.XMLFileName)
    23. Me.AcceptChanges()
    24. MessageBox.Show("Die Monatsdaten wurden erfolgreich gespeichert." & Environment.NewLine & "Datei: " & _filePathsConfig.XMLFileName, "XML-Datei-Erfolg", MessageBoxButtons.OK, MessageBoxIcon.Information)
    25. End Sub
    26. End Class

    War ja ziemlich unschlau: du hattest zwar ein typisiertes Dataset, hast es aber garnet verwendet - und stattdessen iwas komisches in den XmlManager hineingemurxt.

    Wie gesagt: Ist jetzt alles weg, und du kannst dein typDataset anfangen zu verwenden.
    Wichtiges Prinzip: Niemals zur Laufzeit DataTables erstellen, und DataSources zuweisen. Das soll alles immer so bleiben, wie's im Designer eingerichtet wurde.
    Wenn du Daten neu laden willst, dann kannste die alten löschen - mit .Clear, und dann die Tabellen neu befüllen.
    Also die Tabellen, die im typDataset vorhanden sind, leeren und befüllen - nicht versuchen, "einfach" neue, andere, zu nehmen.
    Dateien

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

    Moin moin @ErfinderDesRades

    Hab mir deine Änderungen angesehen. Das erste was mir auffiel, die "alten" XML-Dateien werden nicht eingelesen. Das ist das Schemata ( heißt das so? ) anders.
    Spoiler anzeigen

    Neue XML

    XML-Quellcode

    1. <?xml version="1.0" standalone="yes"?>
    2. <dsWeather xmlns="http://tempuri.org/dsWeather.xsd">
    3. ...
    4. .....
    5. </dsWeather>

    Alte XML

    XML-Quellcode

    1. <?xml version="1.0" encoding="utf-8"?>
    2. <ArrayOfWeatherData xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    3. ...
    4. ....
    5. </ArrayOfWeatherData>


    Bei dem Rest, was du geändert hast, werde ich mich mal reindenken. ;)

    Meine Fragen:
    1.) Brauche ich eigentlich das 2te DT "WeatherYear" für die Berechnungen?
    2.) Mein Versuch mit den Duchschnittsberechnungen klappt nicht so.. Wo steckt da mein Fehler?
    Asperger Autistin. Brauche immer etwas um gewisse Sachen zu verstehen. :huh:
    Das erste was mir auffiel, die "alten" XML-Dateien werden nicht eingelesen.
    ja, das typDataset speichert sich mit etwas anderem Xml ab als dein selbstgebasteltes untypisiertes.
    Wenn du den alten Kram erhalten willst, kannste die Dateien mit Notepad++ - Textersatz aufs neue Format umstellen.

    Amelie schrieb:

    1.) Brauche ich eigentlich das 2te DT "WeatherYear" für die Berechnungen?
    Das musst du doch wissen.
    ich hab jdfs. nix gesehen, wozu das gebraucht würde.
    Und vom Datenmodell her ist das eh ein Riesen-Fehler, eine zweite Tabelle zu bauen, genau wie die erste, nur unter anderem Namen.

    Amelie schrieb:


    2.) Mein Versuch mit den Duchschnittsberechnungen klappt nicht so.. Wo steckt da mein Fehler?
    Weiss nicht - hab ich nicht geguckt, und guck ich erstmal auch nicht.
    Wäre auch glaub ein neuer Forum-Thread, wo du dieses Problem ühaupt nachvollziehbar erläuterst.

    Amelie schrieb:

    mal reindenken
    Jo, das wär wichtig.
    Insbesondere, wie ich die BL in einer Partialen Klasse des typDatasets angelegt hab, das dürfte dir neu sein.
    Und dieser Ansatz ist noch enorm ausbaufähig. (Etwa Durchschnittsberechnungen sind auch business-Logik)
    @ErfinderDesRades

    Das mit den "alten" XML-Dateien, da habe ich mir etwas gebastelt, klappt super.
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Public Class Form1
    2. Private Sub OpenDirectoryButton_Click(sender As Object, e As EventArgs) Handles OpenDirectoryButton.Click
    3. Dim folderBrowserDialog As New FolderBrowserDialog()
    4. If folderBrowserDialog.ShowDialog() = DialogResult.OK Then
    5. Dim fileNames As String() = Directory.GetFiles(folderBrowserDialog.SelectedPath, "*.xml")
    6. For Each fileName In fileNames
    7. ReplaceXmlFile(fileName)
    8. Next
    9. MessageBox.Show("Alle XML-Dateien wurden erfolgreich aktualisiert.", "Erledigt", MessageBoxButtons.OK, MessageBoxIcon.Information)
    10. End If
    11. End Sub
    12. Private Sub ReplaceXmlFile(filePath As String)
    13. Dim xmlContent As String = File.ReadAllText(filePath)
    14. xmlContent = xmlContent.Replace("<?xml version=""1.0"" encoding=""utf-8""?>", "<?xml version=""1.0"" standalone=""yes""?>")
    15. xmlContent = xmlContent.Replace("<ArrayOfWeatherData", "<dsWeather xmlns=""http://tempuri.org/dsWeather.xsd"">")
    16. xmlContent = xmlContent.Replace("</ArrayOfWeatherData>", "</dsWeather>")
    17. File.WriteAllText(filePath, xmlContent)
    18. End Sub
    19. End Class



    Datenmodell her ist das eh ein Riesen-Fehler

    Ich habe darüber einiges gelesen und da wurden oft die Dtaen von einer zu anderen copiert usw..
    Naja es zeigt nur auf, das ich gerade bzgl. DT / DS usw noch viel lernen muss.

    BL in einer Partialen Klasse des typDatasets

    Ja steige da noch nicht so richtig durch, aber bei Zeiten stelle ich Fragen. :)
    Asperger Autistin. Brauche immer etwas um gewisse Sachen zu verstehen. :huh:

    Amelie schrieb:

    Ja steige da noch nicht so richtig durch
    naja. gugge post#2, also es sind lumpige 29 Zeilen.
    Bzw zwei Public Methoden, nämlich LoadXml() und SaveXml().
    Und eine Private Methode namens GenerateMonth()
    Also zumindest was da passiert müsste doch sonnenklar sein: Speichern und Laden, und wenn bei letzterem eine Datei noch nicht vorhanden, dann eben Generieren.
    @ErfinderDesRades

    ​Partialen Klasse...


    Das war mir neu; habe mich mal etwas eingelesen.
    Wenn ich das nun richtig verstanden habe, können das z.B. 2 Dateien sein die eine gemeinsame Klasse bilden.
    Spoiler anzeigen

    Datei1.vb:

    VB.NET-Quellcode

    1. Partial Class FilePathsConfig
    2. Public ReadOnly DataSource As String = "A:\Wetterdaten\"
    3. End Class

    Datei2.vb:

    VB.NET-Quellcode

    1. Partial Class FilePathsConfig
    2. Public ReadOnly BackupDirectory As String = "WeatherBackup"
    3. Public ReadOnly OldBackupDirectory As String = "OldWeatherBackup"
    4. Public Sub CreateBackUp()
    5. Debug.WriteLine(DataSource)
    6. End Sub
    7. End Class

    Asperger Autistin. Brauche immer etwas um gewisse Sachen zu verstehen. :huh:
    Richtig. Das hast Du übrigens in jedem VB.NET-Projekt. Du hast anfangs Deine Datei Form1.VB mit Public Class Form1 und Du hast die Form1.Designer.VB mit Partial Class Form1.
    Ich verwende solch eine Aufteilung pro Klasse mit noch viel mehr Dateien, um eine Übersicht über verschiedene Vorgänge zu behalten. Teilweise habe ich bis zu 7 Dateien pro Klasse - wenn nichts spezielles dazukommt.
    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

    Also ich habe nun noch ein wenig gelesen und dann von Grund auf neu begonnen.

    Eine Klasse aufgeteilt in 3 Dateien. Bestimmt hätte man noch mehr teilen können oder? :?:
    Aber was mir wieder aufgefallen ist im Zuge mit dem OOP und dem SRP das nach meinem jetzigen Verständnis Code manchmal zu "aufgebläht" wirkt.

    Ich hoffe mal das mein neuer Ansatz besser ist :)

    Beispiel:
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Public Property Variable As String = "huibu"
    2. ' oder so:
    3. Private _variable As String = "huibu"
    4. Public Property Variable As String
    5. Get
    6. Return _variable
    7. End Get
    8. Set(value As String)
    9. _variable = value
    10. End Set
    11. End Property



    Hier mal der Begin des "Neuaufbaus" ^^
    Spoiler anzeigen

    BackUp/Restore clsBackupservice.vb

    VB.NET-Quellcode

    1. Partial Public Class WeatherDataService
    2. ''' <summary>
    3. ''' Erstellt ein Backup der Wetterdaten.
    4. ''' </summary>
    5. Public Sub CreateBackUp()
    6. Try
    7. Dim timestamp As String = GenerateTimestamp()
    8. Dim zipFileName As String = $"Backup_{timestamp}.zip"
    9. Dim targetDirectory As String = GetBackUpPath()
    10. If Not Directory.Exists(targetDirectory) Then
    11. Directory.CreateDirectory(targetDirectory)
    12. End If
    13. Dim zipFilePath As String = Path.Combine(targetDirectory, zipFileName)
    14. If ZipFileTimeOut() Then
    15. ZipFile.CreateFromDirectory(SourceDirectory, zipFilePath)
    16. RaiseBackUpCreated(EventArgs.Empty)
    17. Else
    18. RaiseBackUpTimeOut(EventArgs.Empty)
    19. End If
    20. Catch ex As DirectoryNotFoundException
    21. RaiseDirectoryCreationFailedEvent(EventArgs.Empty)
    22. Catch ex As Exception
    23. RaiseDirectoryCreationFailedEvent(EventArgs.Empty)
    24. End Try
    25. End Sub
    26. ''' <summary>
    27. ''' Stellt die Wetterdaten aus einer ZIP-Datei wieder her.
    28. ''' </summary>
    29. Public Sub CreateRestore()
    30. Try
    31. Dim restoreDrive As String = Me.TargetDrive
    32. If Not String.IsNullOrEmpty(restoreDrive) Then
    33. Dim openFileDialog As New OpenFileDialog()
    34. openFileDialog.Title = "Wiederherstellung - Quelldatei auswählen"
    35. openFileDialog.Filter = "ZIP-Dateien (*.zip)|*.zip"
    36. openFileDialog.InitialDirectory = Path.Combine(restoreDrive, BackupDirectory)
    37. If openFileDialog.ShowDialog() = DialogResult.OK Then
    38. Dim zipFilePath As String = openFileDialog.FileName
    39. Dim targetDirectory As String = Me.SourceDirectory
    40. Dim extractedFiles As New List(Of String)()
    41. Using archive As ZipArchive = ZipFile.OpenRead(zipFilePath)
    42. For Each entry As ZipArchiveEntry In archive.Entries
    43. Dim entryPath As String = Path.Combine(targetDirectory, entry.FullName)
    44. If File.Exists(entryPath) Then
    45. File.Delete(entryPath)
    46. End If
    47. entry.ExtractToFile(entryPath)
    48. extractedFiles.Add(entryPath)
    49. Next
    50. End Using
    51. RaiseRestoreCreated(extractedFiles)
    52. End If
    53. Else
    54. Throw New InvalidOperationException("Das Ziellaufwerk ist nicht festgelegt.")
    55. End If
    56. Catch ex As Exception
    57. RaiseDirectoryCreationFailedEvent(EventArgs.Empty)
    58. End Try
    59. End Sub
    60. End Class

    Aufräumen clscleanupserve.vb

    VB.NET-Quellcode

    1. Partial Public Class WeatherDataService
    2. ''' <summary>
    3. ''' Verschiebt alte Backups in das OldBackupDirectory und löscht überschüssige alte Backups.
    4. ''' </summary>
    5. Public Sub MoveOldBackups()
    6. If DeleteOldbackup Then
    7. If String.IsNullOrEmpty(TargetDrive) Then
    8. MessageBox.Show("Das Ziellaufwerk ist nicht festgelegt.", "Wetterstation Fehler", MessageBoxButtons.OK, MessageBoxIcon.Error)
    9. Return
    10. End If
    11. MoveBackupsToOldBackupDirectory(CountBackup)
    12. CleanUpOldBackupDirectory(CountOldBackups)
    13. MessageBox.Show("Das Bereinigen der Daten war erfolgreich.", "Wetterstation Info", MessageBoxButtons.OK, MessageBoxIcon.Information)
    14. End If
    15. End Sub
    16. Private Sub MoveBackupsToOldBackupDirectory(backupCountToKeep As Integer)
    17. If Not Directory.Exists(GetOldBackupPath()) Then
    18. Directory.CreateDirectory(GetOldBackupPath())
    19. End If
    20. Dim backupFiles As String() = Directory.GetFiles(GetBackUpPath(), "*.zip")
    21. Dim backupFileCount As Integer = backupFiles.Length
    22. If backupFileCount > backupCountToKeep Then
    23. Array.Sort(backupFiles, New Comparison(Of String)(Function(x, y) File.GetLastWriteTime(x).CompareTo(File.GetLastWriteTime(y))))
    24. For i As Integer = 0 To backupFileCount - backupCountToKeep - 1
    25. Dim backupFile As String = backupFiles(i)
    26. Dim destinationFile As String = Path.Combine(GetOldBackupPath(), Path.GetFileName(backupFile))
    27. Try
    28. File.Move(backupFile, destinationFile)
    29. Debug.WriteLine($"Backup-Datei '{Path.GetFileName(backupFile)}' wurde ins OldBackupDirectory verschoben.")
    30. Catch ex As Exception
    31. MessageBox.Show($"Fehler beim Verschieben der Backup-Datei '{Path.GetFileName(backupFile)}' ins OldBackupDirectory: {ex.Message}", "Wetterstation Fehler", MessageBoxButtons.OK, MessageBoxIcon.Error)
    32. End Try
    33. Next
    34. End If
    35. End Sub
    36. Private Sub CleanUpOldBackupDirectory(oldBackupCountToKeep As Integer)
    37. Dim oldBackupFiles As String() = Directory.GetFiles(GetOldBackupPath(), "*.zip")
    38. If oldBackupFiles.Length > oldBackupCountToKeep Then
    39. Array.Sort(oldBackupFiles, New Comparison(Of String)(Function(x, y) File.GetLastWriteTime(x).CompareTo(File.GetLastWriteTime(y))))
    40. For i As Integer = 0 To oldBackupFiles.Length - oldBackupCountToKeep - 1
    41. Try
    42. File.Delete(oldBackupFiles(i))
    43. Debug.WriteLine($"Backup-Datei '{Path.GetFileName(oldBackupFiles(i))}' wurde aus dem OldBackupDirectory gelöscht.")
    44. Catch ex As Exception
    45. MessageBox.Show($"Fehler beim Löschen der Backup-Datei '{Path.GetFileName(oldBackupFiles(i))}' aus dem OldBackupDirectory: {ex.Message}", "Wetterstation Fehler", MessageBoxButtons.OK, MessageBoxIcon.Error)
    46. End Try
    47. Next
    48. End If
    49. End Sub
    50. End Class

    Dateien / Verzeichnise.. clsdirfileservice.vb

    VB.NET-Quellcode

    1. Partial Public Class WeatherDataService
    2. Public Event BackUpCreatedSuccess As EventHandler(Of EventArgs)
    3. Public Event RestoreCreatedSuccess As EventHandler(Of EventArgs)
    4. Public Event DirectoryCreationFailed As EventHandler(Of EventArgs)
    5. Public Event BackUpTimeOut As EventHandler(Of EventArgs)
    6. Public Event DriveFailed As EventHandler(Of EventArgs)
    7. Public ReadOnly userFolderPath As String = Path.GetFullPath(Environment.GetFolderPath(Environment.SpecialFolder.CommonDocuments))
    8. Public ReadOnly datapath As String = "Wetterdaten\"
    9. Public ReadOnly BackupDirectory As String = "WSBackup\"
    10. Public ReadOnly OldBackupDirectory As String = "WSoldBackup\"
    11. Public ReadOnly filePräfix As String = ".xml"
    12. Public Property TargetDrive As String
    13. Public Property TimeOut As Integer = 1
    14. Public Property DeleteOldbackup As Boolean
    15. Public Property OnlyUSB As Boolean
    16. Public Property CountBackup As Integer = 2
    17. Public Property CountOldBackups As Integer = 3
    18. Public _dtpDatum As DateTimePicker
    19. Private _year As String
    20. Public Property Year As String
    21. Get
    22. Return _year
    23. End Get
    24. Set(value As String)
    25. _year = value
    26. End Set
    27. End Property
    28. Public Sub CreateSubdirectoryWithYear(dtpDatum As DateTimePicker)
    29. _year = dtpDatum.Value.Year.ToString()
    30. Dim subdirectoryPath As String = Path.Combine(userFolderPath, datapath, _year)
    31. If Not Directory.Exists(subdirectoryPath) Then
    32. Directory.CreateDirectory(subdirectoryPath)
    33. MessageBox.Show("Das Unterverzeichnis " & subdirectoryPath & " wurde erfolgreich erstellt.", "Unterverzeichnis erstellt", MessageBoxButtons.OK, MessageBoxIcon.Information)
    34. End If
    35. ' Weitere Aktionen mit dem Unterverzeichnis...
    36. End Sub
    37. Public Function CountOldBackup() As Integer
    38. If String.IsNullOrEmpty(GetBackUpPath()) OrElse Not Directory.Exists(GetBackUpPath()) Then
    39. Return 0
    40. End If
    41. Dim oldBackupFiles As String() = Directory.GetFiles(GetBackUpPath(), "*.zip")
    42. If oldBackupFiles.Length > CountBackup Then
    43. Return oldBackupFiles.Length
    44. Else
    45. Return 0
    46. End If
    47. End Function
    48. Public ReadOnly Property XMLFileName As String
    49. Get
    50. Return Path.Combine("cc", filePräfix)
    51. End Get
    52. End Property
    53. Public Function GetMainDirectory() As String
    54. Dim mainDirectory As String = Path.Combine(userFolderPath, datapath)
    55. Return mainDirectory
    56. End Function
    57. Public Function GetBackUpPath() As String
    58. Dim backuppath As String = Path.Combine(TargetDrive, BackupDirectory)
    59. Return backuppath
    60. End Function
    61. Public Function GetOldBackupPath() As String
    62. Dim oldbackuppath As String = Path.Combine(TargetDrive, OldBackupDirectory)
    63. Return oldbackuppath
    64. End Function
    65. Public Function GenerateTimestamp() As String
    66. Dim timestamp As String = DateTime.Now.ToString("ddMMyyyy_HHmm")
    67. Return timestamp
    68. End Function
    69. Public Function ZipFileTimeOut() As Boolean
    70. Static lastZipCreationTime As DateTime = DateTime.MinValue
    71. Dim currentTime As DateTime = DateTime.Now
    72. Dim timeDifference As TimeSpan = currentTime - lastZipCreationTime
    73. Dim minimumDelay As TimeSpan = TimeSpan.FromMinutes(TimeOut)
    74. If timeDifference >= minimumDelay Then
    75. lastZipCreationTime = currentTime
    76. Return True
    77. Else
    78. Return False
    79. End If
    80. End Function
    81. Public Function GetDriveList() As List(Of String)
    82. Dim driveList As New List(Of String)()
    83. Try
    84. Dim drives As DriveInfo() = DriveInfo.GetDrives()
    85. For Each drive As DriveInfo In drives
    86. If OnlyUSB AndAlso drive.DriveType = DriveType.Removable Then
    87. driveList.Add(drive.Name)
    88. Debug.WriteLine(drive.Name)
    89. ElseIf Not OnlyUSB Then
    90. driveList.Add(drive.Name)
    91. Debug.WriteLine(drive.Name)
    92. End If
    93. Next
    94. Catch ex As Exception
    95. RaiseDriveFailedEvent(EventArgs.Empty)
    96. End Try
    97. Return driveList
    98. End Function
    99. Protected Sub RaiseRestoreCreated(extractedFiles As List(Of String))
    100. Dim message As String = "Folgende Dateien wurden erfolgreich wiederhergestellt:" & Environment.NewLine
    101. For Each file As String In extractedFiles
    102. message &= file & Environment.NewLine
    103. Next
    104. MessageBox.Show(message, "Wetterstation Info", MessageBoxButtons.OK, MessageBoxIcon.Information)
    105. 'RaiseEvent RestoreCreatedSuccess(Me, EventArgs.Empty)
    106. End Sub
    107. Protected Sub RaiseBackUpTimeOut(e As EventArgs)
    108. RaiseEvent BackUpTimeOut(Me, e)
    109. End Sub
    110. Protected Sub RaiseBackUpCreated(e As EventArgs)
    111. RaiseEvent BackUpCreatedSuccess(Me, e)
    112. End Sub
    113. Protected Sub RaiseRestoreCreated(e As EventArgs)
    114. RaiseEvent RestoreCreatedSuccess(Me, e)
    115. End Sub
    116. Protected Sub RaiseDirectoryCreationFailedEvent(e As EventArgs)
    117. RaiseEvent DirectoryCreationFailed(Me, e)
    118. End Sub
    119. Protected Sub RaiseDriveFailedEvent(e As EventArgs)
    120. RaiseEvent DriveFailed(Me, e)
    121. End Sub
    122. End Class

    Asperger Autistin. Brauche immer etwas um gewisse Sachen zu verstehen. :huh:
    Zu post#8: Jo, man kann mit partialen Klassen auch Code-Strukturierung betreiben - ist zB eine gute Alternative für die mir verhassten Regions.



    Aber unverzichtbar ist dieses MIttel, wenn mit Designern gearbeitet wird, wie dem Form-Designer.
    Und der Dataset-Designer ist auch so einer, und ist ein echtes Monstrum.
    Der generiert nicht nur eine Partiale Klasse für das Dataset selbst, sondern für jede enthaltene Tabelle jeweils zwei weitere partiale Klassen: eine Klasse für die Table, eine Klasse für die TableRow.

    Dieses System generierter Klassen ist die OOP-Darstellung des im Dataset formulierten Datenmodells.
    Und alle diese partialen Klassen kann man mit eigenen partialen Klassen erweitern, und BusyiessLogik einbauen, dasses nur so kracht.
    Daher schreibe ich so gut wie nie eigene BL-Klassen - ich erweiter immer nur die SteilVorlagen des Dataset-Designers.




    @Amelie: Tja, du hast leider kein strukturiertes Datenmodell, sondern für jeden Monat eine Datei.
    Das zwingt dich natürlich zu irrsinnig aufwändiger Dateiverarbeitungs-Logik.
    Hättest du ein strukturiertes Datenmodell, wo in einem Dataset Monat und Wetter als verknüpfte Tabellen angelegt wären, dann würdest du dieses mit jeweils einem Befehl aus einer Datei laden oder speichern können.
    Und du würdest lernen, wie man sowas nach Stand der Technik löst - oder zumindest dich darauf zubewegen.
    Also: lerne Datenmodellierung (es ist nicht schwer). Tuts gibts sogar hier im Datenbank-Tut-Bereich

    ("Stand der Technik" ist natürlich ein schwer zu definierender Begriff.
    Aber seine Daten in viele Dateien aufteilen ist sicherlich nicht Stand der Technik.)

    Dieser Beitrag wurde bereits 4 mal editiert, zuletzt von „ErfinderDesRades“ ()

    @ErfinderDesRades

    Das mit den Regionen finde ich oft sehr hilfreich, wenn ich schon viel Code in einer Datei habe.
    Z.B. auf dem Form, wenn dann die ganzen Steuerelemente zugewiesen werden.
    Hier Teile ich mir das gerne in Regionen ein, klappe die zu und sehe dann was dahinter steckt ohne das ich so ein risiegen Wust von Code überschauen muss.
    Asperger Autistin. Brauche immer etwas um gewisse Sachen zu verstehen. :huh:
    @ErfinderDesRades

    Hättest du ein strukturiertes Datenmodell, wo in einem Dataset Monat und Wetter als verknüpfte Tabellen angelegt


    Ja diese Idee hatte ich schon, aber ist wohl noch etwas viel im Moment.
    Eine kleine Hilfe wäre ja nett. :)

    Selber beschäftige ich mich gerade noch mit Klassen und vor allem, wie ich herausfinde was ich für ein solches Projekt an Variablen , Konstanten usw brauche.
    Sonst ertappe ich mich dabei, das ich immer wieder noch eine Variable einbaue obwohl ich die ggf schon habe usw... ?(
    Asperger Autistin. Brauche immer etwas um gewisse Sachen zu verstehen. :huh:
    was brauchst du beim Datenmodell noch Hilfe?
    Du kannst doch Tabellen im TypDataset anlegen - musste nur tun.
    Tutorials zu den Prinzipien der Datenmodellierung kennste ja - wäre vorteilhaft, die zu berücksichtigen.
    Helfen kannich, wenndu es mal gemacht hast - die Regelverstösse sieht man in einem Screenshot ja sofort.

    Jo, dein CodeWust entsteht ja vor allem deshalb, weil du kein Datenmodell hast.
    Ich hab dir ja bereits 2 Klassen und ca. 300 Zeilen Code ersetzt duch vlt. 40 Zeilen, im Datenmodell angesiedelt.
    Das ist aber nur der Anfang.
    Deine ganzer Dateisystem-Zugriffskram kommt komplett weg, und deine Durchschnittsberechnungen schrumpeln auf DreiZeiler zusammen - wenn du auf eim durchdachten Datenmodelll aufbaust.
    @ErfinderDesRades

    Hättest du ein strukturiertes Datenmodell, wo in einem Dataset Monat und Wetter als verknüpfte Tabellen angelegt


    Hallo

    habe nun mal nebenbei ein neues DataSet und DataTable erstellt.
    Ich hoffe mal das es so in deinem Sinne ist. Ich tue mich grad schwer die "Verknüpfungen" zu sehen... ?(
    Bilder
    • DTDSUbung1.jpg

      509,88 kB, 1.189×800, 148 mal angesehen
    Dateien
    • ÜbungDataSet.zip

      (28,6 kB, 118 mal heruntergeladen, zuletzt: )
    Asperger Autistin. Brauche immer etwas um gewisse Sachen zu verstehen. :huh:
    Grundsätzlich richtig!
    Und sieht auch so aus, als ob du durchaus richtig Verknüpfungen siehst.
    Das sind jdfs. die beiden Tables, die nötig sind, und die Relation (alias "Verknüpfung") dazwischen.
    Und auch die richtige als Parent-Table bestimmt. :thumbsup:

    Aber einige handwerkliche Fehler:
    Absolutely NoGo: deine Tables haben keinen Primärschlüssel. Steht in keinem meiner Tuts, wie unabdingbar PKs für eine DataTable sind?
    Doch bestimmt - ohne das hätte ich das Tut "Grundlagen: Die relationale GrundIdee" doch garnet schreiben können.
    Also deine Tables haben ganz richtig jeweils die Spalte ID, aber man muss per KontextMenu zusätzlich noch festlegen, dass diese Spalte der PK der Table ist (Der Dataset-Designer generiert anhand dieser Information wichtige Properties und Methoden).

    Dann Benamung Benamung Benamung:
    • Der dt-Prefix für die Tables ist üflüssig und störend. Prefixe haben nur sinn, wenn es verschiedene Prefixe gibt. In einem Dataset gibts aber nur DataTables, und wenn man vor jeder ein dt macht, wird dadurch keinerlei nützliche Information gegeben.
    • Und Fremdschlüssel müssen so heissen wie die ParentTable, mit ID angehängt.
      Dann sieht man auf den ersten Blick, dass die PK-Spalte Month.ID verknüpft ist mit Weather.MonthID
      So wie es jetzt ist, kann ich nicht erkennen, welche die FK-Spalte ist, die auf Month.ID verweist.
      (Ich fürchte fast, du hast gar keine FK-Spalte hinzugefügt, sondern einfach irgendeine genommen.)
    So, nu habich reingeguckt, äh - hast du irgendeines meiner Tuts konsultiert, in denen ich Prinzipien zur Datenmodellierung darlege?
    Im Vier-Views-Videos kann man zugucken, da ists aber nicht schriftlich. Man muss halt genau zugucken.
    Hier habichs auch schriftlich gemacht: codeproject.com/Articles/1033145/Databinding-for-Beginners, Abschnitt "Model-GuideLines"

    Dieser Beitrag wurde bereits 4 mal editiert, zuletzt von „ErfinderDesRades“ ()

    @ErfinderDesRades

    So wie es jetzt ist, kann ich nicht erkennen, welche die FK-Spalte ist


    Also habe das nochmals geändert. hoffe es ist besser .... ?(
    Bilder
    • DTDSUbung2.jpg

      261,81 kB, 711×660, 146 mal angesehen
    Asperger Autistin. Brauche immer etwas um gewisse Sachen zu verstehen. :huh:
    An welchem Beispiel aus welchem Tut haste dich dabei orientiert?
    Oder findest du darin auch nur ansatzweise wieder, was ich grad zuvor schrieb?

    ErfinderDesRades schrieb:

    Und Fremdschlüssel müssen so heissen wie die ParentTable, mit ID angehängt.
    Dann sieht man auf den ersten Blick, dass die PK-Spalte Month.ID verknüpft ist mit (FK) Weather.MonthID

    @ErfinderDesRades

    Beispiel aus welchem Tut haste

    Naja ich habe mir die 4 Videos auch immer mal wieder angesehen. Leider finde ich das alles etwas viel auf einmal. Ich werde "erschlagen" von so vielen Infos...
    Aber das liegt halt an meinem Autismus...

    Also habe das nochmals geändert und hoffe die "Beziehungen" stimmen nun. ;)

    Mir ist noch nicht ganz klar wie das dann mit den beiden "DTs" funktionieren wird.

    Vorher war es so gesehen einfach.
    Pro Monat erstelle ich eine XML-Datei ... ;)
    Bilder
    • DTDSUbung3.jpg

      328,03 kB, 795×729, 144 mal angesehen
    Asperger Autistin. Brauche immer etwas um gewisse Sachen zu verstehen. :huh:
    Den Dreh mit den ID-Spalten-Benennungen hast Du noch nicht raus. Ja, jede Tabelle sollte eine ID-Spalte haben. Aber die ID-Spalte der einen sollte nicht an die ID-Spalte der anderen gebunden werden. Vielleicht ist noch nicht ganz klar, was es mit denen auf sich hat. Wenn eine Tabellenzeile hinzukommt, Du also eine neue Weather-Tabellenzeile hinzufügst, bekommt diese Zeile automatisch eine einmalige ID, und zwar schaut das Programm nach, wie die "extremste" ID der bisherigen Zeilen ist und legt noch eine Schippe drauf. Wenn also 3 Zeilen da sind und die haben die IDs -1, -2, -4, dann wird die neue Zeile die ID -5 bekommen. Wenn Du diese ID aber an die ID-Spalte einer anderen Tabelle bindest, geht Dein Programm davon aus, dass die Weather-Zeile mit der ID -2 an den Month-Tabellen-Eintrag gebunden ist, der ebenfalls die ID -2 hat. Spätestens wenn es eine mehr Weather-Tabellenzeilen als Month-Tabellenzeilen gibt, ist eine Verknüpfung nicht mehr möglich, da irgendein Weather-Eintrag keine passende Month-Tabellenzeile mehr findet, da ja die ID der neuen Weatherzeile automatisch festgelegt wird.
    Die Weather-ID darf also nicht an die Month-ID gebunden werden, sondern muss eine eigene Spalte namens MonthID haben. Und diese MonthID bindest Du an die ID der Month-Tabelle. Dann ist ganz einfach festlegbar, an welche Month-Tabellenzeile die neue Weather-Tabellenzeile gebunden werden soll, ohne dass es Probleme gibt. Und wie legt man das dann fest, wenn man eine neue Weatherzeile anlegt? Der Compiler verlangt automatisch die Monthzeile anzugeben, an die gebunden werden soll.

    ABER!

    In beiden Tabellen gibt es eine Monats- und eine Jahresspalte, je mit DateTime als Datentyp. Wozu brauchst Du dann überhaupt 2 Tabellen? Und warum müssen die genannten Spalten vom Typ DateTime sein?
    Wäre es nicht sinnvoller, nur die Weather-Tabelle zu haben und Month* und Year* als Int32 zu definieren, sodass Du bei Month die Monatszahl und bei Year das Jahr als Zahl einträgst?
    Das Speichern pro Monat wird dadurch nicht viel schwerer. Du kannst die gewünschten Zeilen später problemlos filtern, sie in eine temporäre DataTable schreiben und diese dann in einer XML speichern.

    * inkonsistente Benennung der Spalten: Month und Year sind englische Begriffe, aber der Rest ist auf Deutsch.
    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“ ()

    @ErfinderDesRades
    @VaporiZed

    Wäre es nicht sinnvoller, nur die Weather-Tabelle zu haben und Month* und Year* als Int32 zu definieren


    Also mit dem Denkanstoß bin ich nun in meinen Überlegungen soweit gekommen.
    Ich müsste dann im Code die Jahres/Monat Zahlen auswerten und dann entsprechend das DGV befüllen und später wieder speichern.
    Das DGV soll ja schon immer für den ganzen Monat ( wie ein leeres Excel-Sheet ) vorliegen.

    Variablen zum speichern der Daten im DTWeather:
    ID als autoincrement
    Jahr als Int = vom Code gesetztes Jahr
    Monat als Int = vom Code gesetzter Monat
    Tag / Datum als Int = vom Code gesetzter Tag
    Rest der Wetterdaten
    --------------------------------------

    Bei zwei DataTable hätte ich also das DT-Weather mit der "ID" welche mit der neuen "MonthID" im DT-Month gebunden wäre?
    Hier stehe ich grade auf dem Schlauch ...
    In "DT-Month" wird immer der jeweilige Monat und das Jahr ( was vom Code kommt ) gespeichert und das dann mit der "MonthID" der "DT-Weather" verknüpft?

    ---------------------------------------
    Mit den Namen, die habe ich auch nun in "deutsch" geschrieben. Bin bissel durcheinander.
    Das mit den DataSet etc und das mit den ganzen Klassen und dann noch darauf achten das alles OOP konform wird/bleibt... püüüüüühhh

    Aber so langsam habe ich das mit den Klassen ( zumindest hier ) schon gut umgesetzt. Klare Trennung von GUI und Funktionen und nicht alles in eine Klasse packen. Das mit dem "Partial Class" ist schon irgendwie eine feine Sache, auch wenn es teilweise mehr Dateien werden. :)
    Fällt mir manchmal schwer KlassenNamen zu finden und den "Überblick" zu behalten.
    Asperger Autistin. Brauche immer etwas um gewisse Sachen zu verstehen. :huh: