Auftragsbuch mit Dataset, Datagridview und XML-Export

  • VB.NET

Es gibt 97 Antworten in diesem Thema. Der letzte Beitrag () ist von Dksksm.

    ErfinderDesRades schrieb:

    Ein ganz anderes Problem kann entstehen dadurch, dass dein Zähler scheinbar positiv zählt.

    So ist es, ich benötigte eine "laufende Nummer" und war der Meinung, dass die ID mit AI die sinnvollste Variante ist. Es darf halt jede Nr nur 1x vergeben werden und mit diversen Prüfungen, ob in der Datatable oder dem DGV ein Eintrag mit der Nr. schon vorhanden ist, entzieht sich eben noch mehr meinen Kenntnissen.

    ErfinderDesRades schrieb:

    Damit kannst und sollteste leben.
    Das ist nicht wirklich ein Problem.

    Ich frage einfach mal nach, auch wenn ich die Antwort erahne ;) , gibt es denn eine Möglichkeit, die Anwendung unsichtbar zu schließen und wieder zu öffnen? :/

    Madde schrieb:

    dass die ID mit AI die sinnvollste Variante ist. Es darf halt jede Nr nur 1x vergeben werden
    Ja, das ist doch gewährleistet.

    Nicht gewährleistet ist, dass in der Nummern-Reihe keine Lücken auftreten.
    Das kann prinzipiell ja auch nicht gewährleistet werden - wie sollte denn ein solches System damit umgehen, wenn ein Datensatz gelöscht wird?
    Die AutoIncrement-ID ist eine Sache, die Du so lassen solltest, wie sie ist. Wenn Du da was anderes brauchst, pack Dir ne andere ID-Spalte hinzu. Aber führe Dir vor Augen, was EdR andeutet:
    Du hast 20 Zeilen, mit den IDs von 0 bis 19.
    Zeile 15 verweist mit einer Foreign-ID auf Zeile 11. Oder eine Zeile aus einer anderen Tabelle verweist auf Zeile 11 der Haupttabelle. Nun wird jene Zeile 11 gelöscht und das System wäre so eingestellt, dass alles andere nachrücken würde, um die Lücke zu schließen. Dann würde Zeile 12 nun die ID von Zeile 11 bekommen. Und plötzlich verweisen die anderen genannten Zeilen, die gerade noch auf die gelöschte Zeile verwiesen haben, plötzlich auf eine ganz andere Zeile. Die Folge: Datenchaos!

    Ein Beispiel:
    CompanyTable
    ID
    Name
    0
    Audio
    1
    BWM
    2
    Dummler

    CarTable

    ID
    CompanyID
    Name
    0
    0
    A9
    1
    1
    X5
    2
    2
    Y-Klasse

    Company mit ID 1 (BWM) wird gelöscht, Company mit ID 2 füllt die Lücke und bekommt die ID 1. Nun gehört das Auto X5 zu Dummler und die Y-Klasse gehört zu niemandem mehr! =O
    Daher: Lass die ID-Spalte einfach ihr Ding machen.
    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.
    Ok, habe ich verstanden, es war also der richtige Ansatz mit AI.

    Ich würde dennoch gern verhindern, das der User eine Zeile löscht und dann weitermachen kann (weil eben der gelöschte Datensatz nicht neu vergeben wird, die Nr aber verwendet werden soll)
    Soll heißen, ein Dialog soll sich öffnen, in welchem darauf aufmerksam gemacht wird, dass das Programm jetzt geschlossen und neu gestartet werden muss.
    Kann man das Programm schließen (Application.exit) und gleich wieder öffnen lassen ( evtl. den aktuellen Pfad merken und nutzen )

    Gruß Madde

    EDIT: Hat sich erledigt: Application.Restart() bringt mich hier zum Ziel.

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „Madde“ ()

    WasWieWo? Application.exit bitte nicht. Und dass der User zum Programmneustart aus solch einem Grund aufgerufen wird, sollte nun wirklich nicht vorkommen.
    Gehen wir die Sache anders an: Wenn Du im DGV das Problem mit den IDs hast - dann lass es einfach mit dem DGV. Ich benutze DGVs in solch einem Fall nur zur Anzeige und evtl. zur Bearbeitung der Daten (aber nie der ID!), aber nicht zur Erstellung neuer Datenzeilen. Für solch einen Fall hab ich einen Button, der mit ein Form erzeugt/anzeigt, auf dem ich die Daten einer neuen Zeile eingeben kann. Und wenn man die Bearbeitung abbricht (DialogResult.Cancel), dann wird die Zeile gelöscht. Und wenn man eine neue per Button anlegt, ist es auch mit der ID i.O.
    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.

    Madde schrieb:

    Kann man das Programm schließen (Application.exit) und gleich wieder öffnen lassen
    Guck - du kennst offsichtlich nicht den ObjectBrowser.
    Weil sonst hättest du dir deine Frage selbst beantwortet.
    Hier wird er ein wenig gezeigt: VisualStudio richtig nutzen (Google ist nicht deine Mami)
    Wenn du Application.Exit() bereits kennst, dann such da in der Nähe, und wirst fündig.
    @VaporiZed
    Meine Eingabemaske für die Erstellung eines neuen Auftrages befindet sich auch auf der Main_Form. Da kann ich DialogResult.Cancel wohl nicht einsetzen oder?

    @ErfinderDesRades
    Habe ich tatsächlich noch nicht genutzt. Neben dem Exit sehe ich aber nur den Restart oder gibt es noch andere relevante Befehle für meine Belange.

    ...und mit dem Restart kann ich es mit meinem jetzigen Code nicht machen. Hintergrund ist, dass meine my.settings wegfliegen. Nach dem Restart scheint die Form nicht komplett geladen zu werden.

    Madde schrieb:

    Meine Eingabemaske für die Erstellung eines neuen Auftrages befindet sich auch auf der Main_Form. Da kann ich DialogResult.Cancel wohl nicht einsetzen oder?
    Nope, das klappt dann natürlich nicht. Da wäre zu überlegen, inwieweit Du das so beibehalten willst. Alles auf dem MainForm ist nicht immer zielführend. Allerdings könntest Du es trotzdem hinbekommen. Du nimmst eine Handvoll passender Controls und der User befüllt diese mit Daten. Dann gibt's 2 Buttons: einer löscht alle eingegebenen Daten, einer fügt die Daten zu einer neuen DataTable-Zeile zusammen. Also DeinTds.DieDataTable.AddDieDataTableRow(HierDieGanzenEinzeldaten)
    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.

    Madde schrieb:

    Neben dem Exit sehe ich aber nur den Restart oder gibt es noch andere relevante Befehle für meine Belange.
    Jo genau, darauf wollte ich hinaus.
    Was anderes ist mir nicht bekannt.
    Ich benutze das auch nie, und wüsste auch nicht, wozu dir das jetzt dienlich sein sollte - im Grunde wollte ich dir nur den OB nahebringen.
    Ich denke Application.Restart macht die Anwendung zu und wieder auf.
    Logisch, dass damit der momentane Programm-Zustand (also welches Form du geöffnet hast, welche Dateien geladen, welchen Datensatz angezeigt) - all dieser Kram ist damit natürlich nicht wieder hergestellt.



    my.settings sind mir noch nie davongeflogen.
    Manchmal werden sie nicht gespeichert - insbesondere bei unordentlichen Programm-Abbrüchen.
    Na da guck doch einfach mal im OB, obs da was gibt, was das könnte - wenn das das Problem ist.
    Ich würde in Bezug auf AutoIncrement gern nochmal nachhaken, da ich vermute, mich vielleicht falsch ausgedrückt zu haben.
    Es wird ein neuer Auftrag mittels Button gestartet, welcher TblAuftragsbuchBindingSource.AddNew startet. Nun fällt mir ein, dass ich den Auftrag nicht mehr eintragen will und breche es mit TblAuftragsbuchBindingSource.CancelEdit() ab. Die Zeile im DGV wird entfernt und es wurde normalerweise noch nichts an die Datatable gesendet.
    Wo steckt die Information, dass die ID bereits verwendet wurde ( was ja eigentlich so nicht richtig ist ), sodass Diese übersprungen wird.
    Das nichts gespeichert wurde, zeigt ja eigentlich dann der Neustart, die XML wird ja geschrieben und hier bleibt die angefangene Zeile "außen vor".

    Die XML mal eben nach dem Abbruch neu zu laden funktioniert leider nicht.
    Ich benötige irgendwie den Zustand vor dem TblAuftragsbuchBindingSource.AddNew

    Vielleicht habt ihr ja doch noch eine Idee und ich hoffe, ich nerve damit nicht aber der Application.Restart ist tatsächlich keine gute Lösung.

    Gruß Madde

    Madde schrieb:

    Wo steckt die Information, dass die ID bereits verwendet wurde ( was ja eigentlich so nicht richtig ist ), sodass Diese übersprungen wird.
    Da ist irgendwo ein Feld in der DataTable-Klasse.
    Auf das wir absolut keinen Zugriff haben.

    Madde schrieb:

    Ich benötige irgendwie den Zustand vor dem TblAuftragsbuchBindingSource.AddNew
    Gibts nicht.
    Soweit ich weiss. Aber vlt. kann man was hacken, etwa DataTable.AutoIncrementStart verändern - probiert hab ich das noch nie.

    Und ich denke nachwievor, dass du nur denkst, dass du das benötigst.
    Oder erklär mir, wozu das nötig ist.

    Vielleicht kannste mich überzeugen, dann helfe ich dir, einen Algo auszudenken, mit dem man das AutoIncrement vielleicht ersetzen kann, das Böse.

    ErfinderDesRades schrieb:

    Oder erklär mir, wozu das nötig ist.


    Ich habe jetzt umgedacht und lasse den TblAuftragsbuchBindingSource.CancelEdit() weg, leere nur die Eingabefelder und lasse die Zeile bis zur nächste Neueingabe stehen. Ich kann damit leben und es ist auch für den User plausibel.
    Das betrifft aber jetzt eben nur den Abbruch einer Eingabe.
    Was mich stört, ist, wenn die fertige, im Dataset und als XML gespeicherte letzte Zeile gelöscht wird und daraufhin ein neuer Auftrag gestartet wird, überspringt er die letzte Nr. Aus diesem Grund ist aktuell noch der Restart drin, was aber halt unsauber ist, da auch meine my.settings verschwinden.
    Hier mein Code für den Zeile-Löschen-Teil.

    VB.NET-Quellcode

    1. Private Sub ButtonDelete_Click(sender As Object, e As EventArgs) Handles ButtonDelete.Click
    2. If dgv.SelectedRows.Count = 0 Then
    3. MsgBox("Die zu löschende Zeile muss markiert sein", MsgBoxStyle.Information, "Fehler")
    4. Return
    5. End If
    6. If MsgBox("Zeile wirklich löschen? Dieser Vorgang kann nicht rückgängig gemacht werden!", CType(MsgBoxStyle.Exclamation + MsgBoxStyle.OkCancel, Global.Microsoft.VisualBasic.MsgBoxStyle), "Unwiderrufliches Löschen") = MsgBoxResult.Cancel Then Return
    7. dgv.Rows.Remove(dgv.CurrentRow)
    8. TblAuftragsbuchBindingSource.EndEdit()
    9. Save()
    10. 'MsgBox("Es wird nun ein Neustart des Auftragsbuches durchgeführt", MsgBoxStyle.Information, "Neustart")
    11. 'Application.Restart()
    12. End Sub


    Nur Notwendigkeit: Aktuell werden die Aufträge digital ( Eine Excel-Version dieses Auftragsbuches, daher dieses Projekt ) sowie analog ( mit einem Paginierstempel ) erfasst. Somit sollten die beiden Dinge übereinstimmen. Ob es sinnig ist, beides zu führen, sei dahingestellt und Ziel ist es natürlich, nur das digitale Auftragsbuch zu führen. Es sollte aktuell aber einer Testphase unterliegen und somit beides übereinstimmen.
    Der Zweite, eventuell zu überdenkende, weil wahrscheinlich für das Programm zu aufwendige Grund, ist die Ästhetik. Es ist einfach schön, wenn die Auftragsnummern ohne Unterbrechung durchlaufen. Das mittendrin gelöschte Aufträge diesen Gedanken durchqueren, ist mir natürlich bewusst ;)

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

    Nochmal zum DGV_Cellformatting.

    Ich glaube, ich hab eine Vermutung, warum er mein Lieferwunschdatum oder Eingangsdatum farbig nicht hervorhebt. Beide Daten werden mittels DTP im Format System.DateTime abgelegt. Ich glaube das Problem ist, dass der Zeitstempel bis auf die letzte "Nanosekunde" genutzt wird. In der XML habe ich mal den Zeitstempel verwendet und wie folgt eingesetzt. Nun wird auch die Zelle entsprechend farbig gekennzeichnet.

    VB.NET-Quellcode

    1. If e.ColumnIndex = LieferdatumDataGridViewTextBoxColumn.DisplayIndex Then
    2. If e.Value = "2021-06-09T12:54:30.8338913+02:00" Then
    3. e.CellStyle.BackColor = Color.LightPink
    4. '.......
    5. End If


    Wie kann ich diese Daten für die Ablage in der XML soweit formatieren, dass sie mit Date.Now vergleichbar sind? Tag/Monat/Jahr wäre völlig ausreichend.

    Gruß Madde

    Madde schrieb:

    If e.Value = "2021-06-09T12:54:30.8338913+02:00" Then
    I whipser to the sound of Option Strict On …
    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.
    Ich würde nochmals um Eure Hilfe bitten.

    Es geht um Post #23.
    Die Vorgehensweise, jeden einzelnen Auftrag zu markieren und mittels Button als "Erledigt" zu kennzeichnen ist in Ordnung aber irgendwie nicht das Wunschergebnis.
    Meine Spielereien mit Cellklick oder ähnlichen Checkbox-Events haben alle zu keinem Ergebnis geführt. Immer wurden alle bislang markierten Checkboxen mit in die neue Eingabe aufgenommen und entsprechend geändert.
    Wie kann ich das ändern, dass bereits als "True" gesetzte Zeilen nicht mehr berücksichtigt werden?

    Beispiel:
    10 Einträge sind eingetragen. 1-5 sind bereits als "erledigt" markiert, mit Datum und Zeitstempel.
    Nun sollen die Aufträge 6-9 markiert werden und der Datum und Zeitstempel auch nur auf diese Zeilen angewendet werden und nicht wie bislang in meinen Versuchen dann erneut auf alle Markierten.

    Gruß Madde
    Nun, dazu musst Du herausfinden, welche Zeilen aus Sicht der BS markiert sind. Im besten Fall klappt es, indem Du die SelectedCells des DGV hernimmst, davon jeweils den RowIndex, dann mit einer For-Schleife durch all diese durchgehst und dann eben den Doppelcast auf DeineBindingSource(DerAktuelleIndexDerForSchleife) anwendest und die Daten setzt.
    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.
    Da Du tDS und BS im Einsatz hast, wird es wohl so ungefähr gehen, wenn Du das Festsetzen der Status so machst, dass Du Zellen oder Zeilen anwählst, und dann einen Button drückst:

    VB.NET-Quellcode

    1. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    2. For Each SelectedRowIndex In DeinDGV.SelectedCells.Cast(Of DataGridViewCell).Select(Function(x) x.RowIndex).Distinct
    3. DirectCast(DirectCast(DeineBS(SelectedRowIndex), Data.DataRowView).Row, DeinTds.DeineAuftragsRow).IstErledigt = True
    4. Next
    5. End Sub

    Der komplexe Ausdruck nach For Each SelectedRowIndex In ist nur dafür da, um von allen selektierten Zellen die Zeilenindizes zu erhalten, und zwar nur einmal. Wenn Du durch den durchsteigst, ist gut, ansonsten nimm ihn in ner ruhigen Minute mal auseinander.
    In der DoppelCast-Zeile wird immer eine bestimmte Zeile in der DataTable hergenommen (und zwar eine, die auch im DGV selektiert wurde)), in Deine Auftragszeile gecastet und der Status gesetzt.
    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.
    Dickes Danke! Daraus habe ich nun folgendes gemacht.
    Ich habe es in ein CellValueChanged gepackt, sodass die Änderung "fast" gleich angezeigt wird. Per Button geht es dann ins Dataset und in die XML.
    Einziger Schönheitsfehler ist das "fast", ich muss nach dem Checkbox aktivieren ein weiteres mal irgendwo ins dgv klicken, damit der Eintrag kommt.
    Gibt es die Möglichkeit, sofort nach Aktivierung die Änderung darzustellen?
    Hier nun der Code.

    VB.NET-Quellcode

    1. Private Sub dgv_CellValueChanged(sender As Object, e As DataGridViewCellEventArgs) Handles dgv.CellValueChanged
    2. For Each SelectedRowIndex In dgv.SelectedCells.Cast(Of DataGridViewCell).Select(Function(x) x.RowIndex).Distinct
    3. Dim Row = DirectCast(DirectCast(TblAuftragsbuchBindingSource(SelectedRowIndex), Data.DataRowView).Row, dtsAuftragsbuch.tblAuftragsbuchRow)
    4. If DirectCast(DirectCast(TblAuftragsbuchBindingSource(SelectedRowIndex), Data.DataRowView).Row, dtsAuftragsbuch.tblAuftragsbuchRow).Ausgeliefert = True Then
    5. If Row.Versandart = "Fahrer" Then
    6. Row.Lieferart = "Ausgeliefert"
    7. ElseIf Row.Versandart = "UPS" Then
    8. Row.Lieferart = "Versandt"
    9. Else
    10. Row.Lieferart = "Abgeholt"
    11. End If
    12. Row.Datum = Date.Today
    13. Row.Zeit = CDate(DateTime.Now.ToString("HH:mm"))
    14. Row.Abweichung = CStr(CInt((Row.Lieferdatum.Date - Row.Datum.Date).TotalDays))
    15. '.............

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