pat.bat
Goto Top

Kalenderselektion in Textdatei speichern und lesen mit VB.NET

Hallo zusammen,

ich habe derzeit ein kleines Tool in Überlegung womit man in einer einfachen Kalendermaske (MonthCalendar) auf ein Datum klickt und diese dann in eine textdatei untereinander gespeichert werden.

Soweit so gut.

Das habe ich zurzeit eher einfach gelöst:

Public Class Form1


    Dim DatumListe As String


    Public Sub MonthCalendar1_DateSelected(sender As Object, e As DateRangeEventArgs) Handles MonthCalendar1.DateSelected

        MonthCalendar1.MaxSelectionCount = 1
        Dim Datum As String = MonthCalendar1.SelectionRange.Start.ToShortDateString() + vbNewLine

        System.IO.File.AppendAllText("G:\FD_50_Bank\System\Zahltagskalender\Zahltage2.txt", Datum)  

    End Sub
End Class

Zurzeit speicher ich also einfach die selektierten Tage in eine Textdatei.

Jetzt komm ich aber auf 2, ich nenne es mal, Probleme.

1. möchte ich das Visuel in der VB.NET Maske wiedergeben zb. der Tag farblich marktiert.

und

2. Wenn ich auf einen Tag klicke, der bereits abgespeichert ist, soll dieser wieder gelöscht werden.


Eine Lösung für 1tens fällt mir derzeit nicht ein, da VB.NET nicht viele Möglichkeiten gibt, den Kalender zu formatieren.

zu 2tens fällt mir derzeit nur die Möglichkeit ein, mit einer Schleife durch die Datei zu schauen und das Feld herauszusuchen und den Eintrag zu löschen. Was aber auf Dauer zu Performanceproblemen führen wird (denke ich zumindest).
Eine weitere Möglichkeit wäre eine Access-Datenbank einzubinden, aber ob sich das lohnt?

Oder fällte euch eine bessere Idee ein, die Daten zu speichern und zu laden?


Hintergrund ist, das ein Powershell Skript auf die erstellte Textdatei zugreifen und prüfen soll ob heute einer der hinterlegten Tage ist und das Skript ausführt oder schließt.


Ich danke euch schonmal für eure Tips face-smile

Content-Key: 464347

Url: https://administrator.de/contentid/464347

Printed on: April 25, 2024 at 16:04 o'clock

Member: colinardo
Solution colinardo Jun 20, 2019, updated at Jun 21, 2019 at 06:12:14 (UTC)
Goto Top
Servus @Pat.bat ,
ach da gibt es so viele Möglichkeiten, aber eine Datenbank extra dafür wäre Overkill. Für solche einfachen Dinge eigenen sich heutzutage z.B. XML-Dateien in denen du Daten strukturiert ablegen kannst und welche du hinterher auch wieder strukturiert in PowerShell über ein [XML] Object auslesen kannst.
Da du offentlich in dem Bereich noch etwas unerfahren hantierst belasse ich es erst mal bei einem einfachen Beispiel das du mit etwas Lesen nachvollziehen können solltest:
(Methoden wie XMLSerialization von Objekten (z.B. von DataTables etc.) lasse ich hier mal explizit außen vor denke das wäre noch etwas zu viel für Dich, wäre aber aber eine effektivere Nutzung wenn es um mehr Daten geht als nur ein einfaches Datum)
Imports System.Xml
Imports System.IO
Imports System.Xml.Serialization
Imports System.Globalization

Public Class Form1
    Dim xmlDoc As New XmlDocument
    ' Pfad zum XML Dokument  
    Dim xmlPath As String = Environ("TEMP") & "\" & "daten.xml"  

    Private Sub MonthCalendar1_DateSelected(sender As Object, e As System.Windows.Forms.DateRangeEventArgs) Handles MonthCalendar1.DateSelected
        Dim d As Date
        ' Für jedes slektierte Datum  
        For i = 0 To DateDiff(DateInterval.Day, e.Start, e.End)
            d = e.Start.AddDays(i)
            ' Wenn das Datum bereits markiert ist  
            If MonthCalendar1.BoldedDates.Contains(d) Then
                ' entferne die Markierung  
                MonthCalendar1.RemoveBoldedDate(d)
            Else
                ' Füge Markierung hinzu  
                MonthCalendar1.AddBoldedDate(d)
            End If
            ' Aktualisiere XML im Speicher über Funktion welche Hinzufügen und Entfernen übernimmt  
            UpdateXML(d)
        Next
        ' Aktualisiere markierte Datumswerte im Kalender  
        MonthCalendar1.UpdateBoldedDates()
    End Sub

    Private Sub Form1_FormClosed(sender As Object, e As System.Windows.Forms.FormClosedEventArgs) Handles Me.FormClosed
        ' Speichere XML Datei im Dateisystem  
        xmlDoc.Save(xmlPath)
    End Sub

    Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
        ' Wenn XML Datei existiert lade die Datei und markiere die Werte im Kalender  
        If File.Exists(xmlPath) Then
            Dim node As XmlNode
            xmlDoc.Load(xmlPath)
            For Each node In xmlDoc.SelectNodes("/Data/Date")  
                MonthCalendar1.AddBoldedDate(DateTime.ParseExact(node.InnerText, "dd\.MM\.yyyy", CultureInfo.InvariantCulture))  
            Next
            MonthCalendar1.UpdateBoldedDates()
        Else ' XML-Datei existiert noch nicht, erstelle das Gerüst der Datei im Speicher  
            Dim XmlDeclaration As XmlDeclaration = xmlDoc.CreateXmlDeclaration("1.0", "UTF-8", Nothing)  
            xmlDoc.InsertBefore(XmlDeclaration, xmlDoc.DocumentElement)
            Dim nodeRoot As XmlElement = xmlDoc.CreateElement("Data")  
            xmlDoc.AppendChild(nodeRoot)
        End If
    End Sub
    ' Methode die die XML-Datei im Speicher aktualisiert und die Datumswerte darin aktualisiert  
    Private Sub UpdateXML(ByVal d As Date)
        Dim findNode As XmlElement = xmlDoc.DocumentElement.SelectSingleNode("/Data/Date[. = '" & d.ToString("dd\.MM\.yyyy") & "']")  
        If findNode Is Nothing Then
            Dim nodeDate As XmlElement = xmlDoc.CreateElement("Date")  
            nodeDate.InnerText = d.ToShortDateString()
            xmlDoc.DocumentElement.AppendChild(nodeDate)
        Else
            xmlDoc.DocumentElement.RemoveChild(findNode)
        End If
    End Sub
End Class
(Errorhandling Try Catches etc. für das Beispiel weggelassen)

Das Beispiel benutzt zur Speicherung eine XML-Datei (im Beispiel im Temporären Ordner des Systems abgelegt). Diese wird beim Öffnen erzeugt sofern sie noch nicht existiert. Existiert sie wird sie eingelesen und die Datumswerte dem Kalender als BoldedDates hinzugefügt. Klick der Nutzer nun auf einen Tag oder einen Bereich der noch nicht fett markiert ist werden diese Datumswerte aus der XML-Datei erst einmal im Speicher hinzugefügt und das Datum fett markiert, existieren die Datumswerte werden sie stattdessen entfernt ebenso wie die Markierung.
Schließt der Anwender die Form wird die XML-Datei im Speicher auf die Platte geschrieben.

In Powershell kannst du die Daten aus der XML auch sehr schnell wieder auslesen
$xml = [xml](gc "D:\datei.xml")  
$xml.Data.Date

Kannst du ja nach Gusto anpassen und war nur ein Beispiel von vielen anderen Varianten besonders XMLSerialization bringt da nochmal mehr Komfort. Beispiele wie man sowas auch in Powershell handelt hatte ich hier schon mal im Zusammenhang mit DataTables gepostet.
Powershell Datagridview und XML Datenhaltung
Du kannst natürlich auch eine simple Textdatei dafür nutzen wenn du unbedingt willst, auslesen, in ein Array oder Collection speichern dann im Speicher mit den bekannten Methoden zum Suchen von Keys modifizieren und am Ende wieder zurückschreiben.


Grüße Uwe

Btw. du könntest die ganze Form auch direkt so wie in VB.Net mit Powershell erstellen wenn du möchtest, kenne aber deinen Workflow diesbezüglich nicht und wofür es zum Einsatz kommt.
Member: Pat.bat
Pat.bat Jun 24, 2019 at 05:56:22 (UTC)
Goto Top
Danke für die großartige Hilfe.

Funktioniert bestens so, ich werde die Maske usw mit der Zeit mit Funktionen erweitern, der hier gezeigt Code hilft mir dabei sehr gut.

In die XML Serialization werde ich mich mal einlesen, das gefällt mir.


Mit Powershell das ganze zu machen sehe ich als zu aufwändig, oder? Da ich mit der Zeit die Maske, wie schon erwähnt, noch mit Funktionen und Ansichten erweitern möchte. Dafür eigenet sich der Formeditor ganz gut. Unter umständen werde ich in Zukunft aber auf C# wechseln.

Vielen Dank für die Hilfe.
Member: colinardo
colinardo Jun 24, 2019 updated at 06:22:38 (UTC)
Goto Top
Keine Ursache.
Zitat von @Pat.bat:
Mit Powershell das ganze zu machen sehe ich als zu aufwändig, oder? Da ich mit der Zeit die Maske, wie schon erwähnt, noch mit Funktionen und Ansichten erweitern möchte.
Nicht wirklich, mit entsprechendem Projekt-Editor (wie z.B. von SAPIEN) ist das fast der gleiche Aufwand wie in VS.
Kommt halt auf den Anwendungszweck und das Projekt an.

Unter umständen werde ich in Zukunft aber auf C# wechseln.
Würde ich dir auch sehr ans Herz legen.

Viele Erfolg weiterhin.
Grüße Uwe
Member: Pat.bat
Pat.bat Jun 24, 2019 at 11:04:57 (UTC)
Goto Top
Ich bin jetzt noch auf kleines Problem gestoßen und weiß nicht so recht, wie ich das in meinem Fall lösen kann.

Ich möchte das die XML wie folgt aufgebaut ist:

<data>
    <prozessname>
        <date>24.06.2019</date>
        <date>25.06.2019</date>
    </prozessname>
</data>


Bei mir siehts aber wie folgt aus:

<?xml version="1.0" encoding="UTF-8"?> 
<Data>
  <Prozessname />
  <Date>24.06.2019</Date>
  <Date>25.06.2019</Date>
</Data>

Ich baue als erstes die xml Struktur:

            Dim XmlDeclaration As XmlDeclaration = xmlDoc.CreateXmlDeclaration("1.0", "UTF-8", Nothing)  
            xmlDoc.InsertBefore(XmlDeclaration, xmlDoc.DocumentElement)

            Dim nodeRoot As XmlElement = xmlDoc.CreateElement("Data")  
            xmlDoc.AppendChild(nodeRoot)

            Dim nodeProzess As XmlElement = xmlDoc.CreateElement(currentProzess)
            xmlDoc.DocumentElement.PrependChild(nodeProzess)

Wobei ich hier ja schonmal festlege, das wir Data und Prozessname haben.

Nun soll er mir das Datum in den Prozessnamen Knoten setzen:

Dim findNode As XmlElement = xmlDoc.DocumentElement.SelectSingleNode("/Data/" & currentProzess & "/Date [. = '" & d.ToString("dd\.MM\.yyyy") &  
            "']")  
        If findNode Is Nothing Then

            Dim nodeDate As XmlElement = xmlDoc.CreateElement("Date")  

            nodeDate.InnerText = d.ToShortDateString()
            xmlDoc.DocumentElement.AppendChild(nodeDate)

In der letzten Zeile hätte ich normalerweise
nodeProzess.AppendChild(nodeDate)
genommen, aber diese Variable existiert ja nicht in dieser Methode. Müsste in diesem Fall die Methode zum erstellen der Struktur auf Public setzen, sodass andere Methoden darauf zugreifen können?
Member: colinardo
colinardo Jun 24, 2019 updated at 12:24:16 (UTC)
Goto Top
In der Tat hast du da noch etwas Verständnisprobleme beim Handling von XML-Knoten. Im Normalfall erstellt man die Knoten und hängt sie von der untersten Ebene an die nächst übergeordnete an und am Schluss dann den Teilbaum ins Dokument. Natürlich musst du bei obigem Beispiel auch noch die anderen Methoden beachten und anpassen.

Für currentProzess (Denglisch is in oder wat face-smile) habe ich mal nur zur Demo einen statischen String gesetzt.

Imports System.Xml
Imports System.IO
Imports System.Xml.Serialization
Imports System.Globalization

Public Class Form1
    Dim xmlDoc As New XmlDocument
    Dim xmlPath As String = Environ("TEMP") & "\" & "daten.xml"  
    Dim currentProzess As String = "BlaBlup"  

    Private Sub MonthCalendar1_DateSelected(sender As Object, e As System.Windows.Forms.DateRangeEventArgs) Handles MonthCalendar1.DateSelected
        Dim d As Date
        For i = 0 To DateDiff(DateInterval.Day, e.Start, e.End)
            d = e.Start.AddDays(i)
            If MonthCalendar1.BoldedDates.Contains(d) Then
                MonthCalendar1.RemoveBoldedDate(d)
            Else
                MonthCalendar1.AddBoldedDate(d)
            End If
            UpdateXML(d)
        Next
        MonthCalendar1.UpdateBoldedDates()
    End Sub

    Private Sub Form1_FormClosed(sender As Object, e As System.Windows.Forms.FormClosedEventArgs) Handles Me.FormClosed
        xmlDoc.Save(xmlPath)
    End Sub

    Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
        If File.Exists(xmlPath) Then
            Dim node As XmlNode
            xmlDoc.Load(xmlPath)
            For Each node In xmlDoc.SelectNodes("/Data/" & currentProzess & "/Date")  
                MonthCalendar1.AddBoldedDate(DateTime.ParseExact(node.InnerText, "dd\.MM\.yyyy", CultureInfo.InvariantCulture))  
            Next
            MonthCalendar1.UpdateBoldedDates()
        Else
            Dim XmlDeclaration As XmlDeclaration = xmlDoc.CreateXmlDeclaration("1.0", "UTF-8", Nothing)  
            xmlDoc.InsertBefore(XmlDeclaration, xmlDoc.DocumentElement)
            Dim nodeRoot As XmlElement = xmlDoc.CreateElement("Data")  
            Dim nodeProzess As XmlElement = xmlDoc.CreateElement(currentProzess)
            nodeRoot.AppendChild(nodeProzess)
            xmlDoc.AppendChild(nodeRoot)
        End If
    End Sub

    Private Sub UpdateXML(ByVal d As Date)
        Dim findNode As XmlElement = xmlDoc.SelectSingleNode("/Data/" & currentProzess & "/Date[. = '" & d.ToString("dd\.MM\.yyyy") & "']")  
        If findNode Is Nothing Then
            Dim nodeDate As XmlElement = xmlDoc.CreateElement("Date")  
            nodeDate.InnerText = d.ToShortDateString()
            Dim nodeProzess As XmlElement = xmlDoc.SelectSingleNode("/Data/" & currentProzess)  
            If nodeProzess Is Nothing Then
                nodeProzess = xmlDoc.CreateElement(currentProzess)
                nodeProzess.AppendChild(nodeDate)
                xmlDoc.DocumentElement.AppendChild(nodeProzess)
            Else
                nodeProzess.AppendChild(nodeDate)
            End If
        Else
            findNode.ParentNode.RemoveChild(findNode)
        End If
    End Sub
End Class
Im Normalfall macht man sowas über eine separate Klasse, die lässt sich dann auch gleichzeitig zur Serialization einsetzen und die Daten in eine Datatable/Collection or whatever laden und deren Methoden zum Hinzufügen und Entfernen nutzen.
Wie gesagt das war nur ein Basic-Sample und nichts großartig generalisiertes.