Erweiterter Umgang mit typisiertem DataSet -> Tabellennamen lesen/Namensübergabe etc.

  • VB.NET
  • .NET (FX) 4.0

Es gibt 351 Antworten in diesem Thema. Der letzte Beitrag () ist von tragl.

    Erweiterter Umgang mit typisiertem DataSet -> Tabellennamen lesen/Namensübergabe etc.

    Hallöle.

    Auf Anraten von "Erfinder des Rades" bin ich mit meinem kleinen Projekt auf die XML-Variante mit typisiertem DataSet umgestiegen.
    Am Anfang war darin eine Tabelle "designed", die für den TreeView zuständig ist -> wird in Tree.xml gespeichert. Der Tree gehört "fest" zum Programm
    und ich könnte die zugehörige XML bei z.B. einem Programmupdate mit auf das Netzlaufwerk packen, sodass die dort gemachten Änderungen für alle gelten.

    Anders sieht das jetzt mit den Benutzerdaten aus - die müssen erhalten bleiben. Also wäre mein Weg der, dass ich die anderen Tabellen des DataSets in eine
    andere oder gar mehrere andere XML-Dateien speichere. Technisch sollte das ohne großen Aufwand lösbar sein, allerdings stehe ich vor dem folgenden Problem:

    Arbeite ich z.B. mit einer Form, wo die Tabelle des TreeViews an ein DGV gebunden ist, lassen sich die z.B. Speicherungen wie folgt lösen:

    VB.NET-Quellcode

    1. Private Sub Save()
    2. Me.Validate()
    3. Me.dts.Tree.WriteXml(xml-datei.FullName)
    4. dts.Tree.AcceptChanges()
    5. End Sub


    etc.

    Wie verhält es sich nun wenn ich das Ganze flexibel gestalten will? Ich möchte z.B.

    - Die Tabellennamen aus dem vorhandenen DataSet auslesen
    Die Variante, die mir dazu eingefallen ist, ist die dass ich das DataSet aus der Toolbox auf die Form ziehe (es wird ein Element mit 1 als Zusatz erstellt /
    original DataSet heißt z.B. "dts", erstellt wird das Element im Form-Designer mit "dts1", somit
    lässt sich zumindest mit dem DataSet arbeiten. Die Tabellennamen lese ich dann wie folgt in eine Listbox aus:

    VB.NET-Quellcode

    1. Dim LB As ListBox = frmAuswahlListbox.ListBox1
    2. LB.Items.Clear()
    3. For Each dt As DataTable In dts1.Tables
    4. LB.Items.Add(dt.TableName)
    5. Next

    Ist das eleganter zu lösen?

    - Dann möchte ich die Tabellenstruktur (die Tabellen wurden bisher nur im Designer hinzugefügt samt Spalten, es sind noch keine Daten vorhanden) in
    eine neue XML-Datei speichern.

    Mein Ansatz:

    VB.NET-Quellcode

    1. dts1.Tables(auswahl aus Listbox).WriteXmlSchema(xml-datei.FullName)

    ist das OK so?

    - Im Nachgang möchte ich die Daten dann füllen. Dazu wähle ich mir die erzeugte XML-Datei aus, lasse mir die Tabellen daraus auslesen und in eine ListBox
    übergeben. Nach Auswahl soll das in der gleichen Form vorhandene DataGridView dann mit den Daten gefüllt werden.
    Im TreeView-Beispiel ist die DGV ja an die Tabelle des Trees gebunden, das DGV wird über "dts.Tree.ReadXml(Tree.xml)" gefüllt.

    Hier ist die DGV jedoch für mehrere Tabellen (die ich vorher auswähle) gedacht. Gibt es eine Variante das DataSet mit einer Variablen anzusprechen?
    (z.B. dts.VARIABLE.ReadXml(xml-datei.xml)) - laut IntelliSense jedenfalls nicht. Muss ich hier den Weg wie oben einschlagen, das "dts1"-Element benutzen und
    dann die Tabelle binden?

    VB.NET-Quellcode

    1. dts1.Tables(Tabelle aus Listboxauswahl).Clear
    2. dts1.Tables(Tabelle aus Listboxauswahl).ReadXml(xml-datei.FullName)
    3. dts1.tables(Tabelle aus Listboxauswahl).AcceptChanges()
    4. DGV.DataSource = dts.Tables(Tabelle aus Listboxauswahl)


    Würde das so funzen und wäre das auch so vorgesehen?
    Ich möchte eben ungern für jede Tabelle im DataSet ein gebundenes DGV erstellen, sondern das nach Möglichkeit über eines Steuern.
    Das ganze soll dann die "Verwaltungszentrale der Daten" darstellen, alle weiteren Programmteile (für die anderen User) werden wieder
    über gebundene DGV's bedient werden können.

    Ich hoffe ich konnte alles verständlich rüberbringen :) Würde mich über Rückmeldung (wenn auch Kritik) freuen.
    "Na, wie ist das Wetter bei dir?"
    "Caps Lock."
    "Hä?"
    "Shift ohne Ende!" :thumbsup:
    Sieht mir vor lauter Flexiblität nach eierlegende Wollmilchsau aus.
    Das wird nicht wirklich was.
    Wozu sollte man alle Tabellen in einer Listbox haben wollen? Auch noch verschiedener Datasetse?
    Eine wirkliche Anwendung will etwa die Bestellungen eines Kunden anzeigen - also einen detailliert ausgearbeiteten m:n-View.
    Da kannst du nicht "Kunden" inne Listbox anklicksen, und dann "Bestellungen", und dann "BestellDetails" - und dir als User den View irgendwie zusammenklicksen.
    Sondern für diese Anwendung kann es nur ein Dataset geben (nämlich mit diesen Tabellen darin).
    Und davon ausgehend kannst du eine Oberfläche entwickeln, eine ganz spezifische.

    Also entwickel erstmal deine konkrete Anwendung - und zwar auf typisierte Weise (das mit for each Table in Dataset.Tables ist schon wieder untypisiert).
    Dann entwickel deine zweite konkrete Anwendung.
    Dann untersuche, was die beiden Anwendungen gemeinsam haben, und wo du irgendwie ansetzen kannst, um irgendeine Flexiblität da sinnvoll unterzubringen.

    Nicht mit Flexiblität anfangen, die später nicht gebraucht wird, oder die später nicht mehr durchzuhalten ist.

    Davon kannste deine Tree-Tabelle ja ausnehmen - haste ja schon.
    Son Menü kann man eventuell tatsächlich in mehreren Anwendungen verwenden.
    Obwohl ich da auch Zweifel habe, weil es ist ja schon ziemlich speziell, dass das Menü für manche Benutzer sichtbar ist, für andere nicht...
    Ja gut, wenn beide deine Anwendungen ein so grosses Menü aufweisen müssen, eine Rechte/Rollen-Verwaltung haben, und zwar dieselbe! - dann kann das Menü eventuell wiederverwendbar sein.
    Aber ich sehe eigentlich noch nicht, dass dein User-Rechte-System bisher überhaupt auskonzipiert wäre (sowas ist nämlich U.U. grausig kompliziert).

    Wie gesagt: Mach erst Einzelfälle fertig, und lager dann Dinge als Wiederverwertbar aus, wo es möglich und sinnvoll ist. (Eine Listbox, die TabellenNamen anzeigt scheint mir nicht dazuzugehören).

    Achso, und wie ebenfalls gesagt: Ich lade meine Datasetse immer komplett - da brauch ich nicht irgendeine Tabelle aus einer listbox-Auswahl nachladen.
    Das Nachladen wird ja auch kompliziert, wenn deine Datenmodelle anfangen, komplexer zu werden, also wenn sie Relationen enthalten.
    Bei einem guten Datenmodell, was wirklich etwas modelliert, wofürs sich lohnt, eine Anwendung zu schreiben - da hängt am Ende alles mit allem zusammen, und Nachladen wird zu einer Aufgabe, mit äusserster Sorgfalt und Sachverstand zu implementieren.
    Zum Beispiel Bestellposten kannst du nicht einfach mal so nachladen, wenn zuvor die Artikel, die da bestellt wurden, nicht geladen sind.



    Nochmal zur konkreten Frage:
    Ja - kann man so machen - also ist technisch möglich.
    Im Endeffekt machst du damit aus einer Dataset-Datei mit vielen Tabellen drin eine Ansammlung von Xml-Files, die je eine Tabelle darstellen.
    Die Relationen (also das relationale am relationalen Datenmodell) sind damit verlorengegangen.
    Wozu auch immer das mal gut sein soll.

    Aber mach nur. Ich kenne mich mit dieser "Zerstückelung" nicht gut aus - da kommt bestimmt was bei raus, wo ich was von lernen kann.



    Ach und

    VB.NET-Quellcode

    1. Dim LB As ListBox = frmAuswahlListbox.ListBox1
    2. LB.Items.Clear()
    3. For Each dt As DataTable In dts1.Tables
    4. LB.Items.Add(dt.TableName)
    5. Next
    Das sieht mir wieder sehr danach aus, dass du Code wohingepackt hast, wo er nicht hingehört - am Ende in iein Modul.
    Wo wird frmAuswahlListbox instanziert, also wo steht: dim frmAuswahlListbox = New frmAuswahlListbox() - lass mich raten: nirgends.
    Mit sowas fährst du mittelfristig an die Wand, weil wenn ich richtig liege ist frmAuswahlListbox kein Objekt, sondern ein Datentyp (aus dem man ein Objekt erstellen könnte).
    Bist du glaub schon drauf hingewiesen worden, scheint aber untergegangen - oder?

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

    Mahlzeit!

    Genau deswegen hatte ich ja hier nachgefragt. Also wäre der bessere (erstmal) Weg, mir z.B. unter "Einstellungen" ein TabControl o.ä. einzubauen, wo ich für jede Tabelle ein gebundenes DGV plaziere mit entsprechenden Save & Reload-Buttons?
    Dabei wäre es "vermutlich egal" ob 1 oder 20 XML-Dateien - wegen Relationsmodell allerdings sinnvol, das in eine zu packen, richtig? DAnn kann ich bei Programmstart die eine XML-Datei komplett in's DataSet einlesen "und fertig". Allerdings
    muss das TreeView außenvor bleiben - dann das fällt nicht unter "userdata" und muss updatefähig bleiben.

    Kann ich gerne so machen und wäre auch der unkomplizierteste Weg - wollte aber erstmal abklopfen ob ich das nicht irgendwie "zentral" lösen kann. Ich tu' mich immer schwer damit viele Sachen an vielen Stellen zu bearbeiten,
    wenn's denn auch an einer Stelle möglich wäre.

    ErfinderDesRades schrieb:

    das mit for each Table in Dataset.Tables ist schon wieder untypisiert


    Das ist korrekt, daher auch meine Frage ob das typisiert möglich wäre. Ich wollte mit der Listbox "nur" abfragen, welche Tabellen in dem !einen! DataSet vorhanden sind - ich bleibe vorerst bei einem DataSet - mehrere zu haben empfinde ich als nicht
    sinnvoll für meine kleine Anwendung. Die Anwendung soll dazu gedacht sein, ein paar Leuten das tägliche Arbeiten zu erleichtern - aktuell benutzen wir sehr viele Excel-Dateien (zur Einsicht, als Auswertungen etc.) - was so eine vb.net-Anwendung locker
    besser darstellen kann. Hier geht es darum z.B. einfach "Stammdaten" unserer Fahrzeuge und Mitarbeiter einzusehen, Rohdaten aus dem WaWi-System automatisiert zu verarbeiten und ggf. 1-2 Listen mit Einträgen, die händisch erfolgen zu führen.
    Dazu kommt, dass eine zentrale Stelle Auswertungen der einzelnen Excel-Dokumente zusammenführt mit noch ein paar Zahlen, die die Mitarbeiter "nix angehen". Da unsere IT ein Problem damit hat, so etwas außerhalb unseres
    Warenwirtschaftssystems zu entwickeln bleibt das an den "kleinen Leuten" hängen. Ich soll denen das alles in Excel wieder "dahinklatschen", obwohl das anhand der Datenstruktur wenig Sinn macht.

    Bzgl. der diversen Useransichten: Es wird sicherlich kein ausgeklügeltes Benutzersystem wie man's kennt - aber:
    Der TreeView zeigt am Ende entsprechenden Benutzergruppen das an, was sie sehen sollen. Es wird Benutzergruppen geben, die eben keine Einsicht auf spezielle
    Forms/Inhalt haben sollen/dürfen.

    Das mit der "eierlegenden Wollmilchsau" war auch so von mir gewollt, da ich mir als "admin" die Möglichkeit offen halten möchte Wartungsarbeiten an den Datendateien durchzuführen, ohne
    dabei wieder an's Visual Studio zu müssen oder für 20 Tabellen auch 20 Forms designen muss :)

    Ich bin weiterhin an der Lektüre von Löffelmann (Entwicklerbuch Visual Basic 2005) dran, wo ich nach den ersten Seiten schon Lerneffeckte hatte - Es fehlen ja "nur noch" ca. 900 Seiten :)
    Nichts desto trotz arbeite ich weiterhin an dem Design und an dem Aufbau des Programms und fürchte eben, dass es im Nachgang sehr viel Aufwand ist o.g. einzubauen - aber ich lass' mich gerne eines Besseren
    belehren :)

    Zum Schluss noch;

    ErfinderDesRades schrieb:

    Aber mach nur. Ich kenne mich mit dieser "Zerstückelung" nicht gut aus - da kommt bestimmt was bei raus, wo ich was von lernen kann.


    Es wäre schön, dir das beweisen zu können - allerdings merke ich immer mehr dass du mit deinen Vermutungen und Wegweisungen Recht hast. Evtl. stellt sich das an der einen oder anderen Stelle ja noch
    anders raus :)

    ErfinderDesRades schrieb:

    Wo wird frmAuswahlListbox instanziert, also wo steht: dim frmAuswahlListbox = New frmAuswahlListbox() - lass mich raten: nirgends.


    Soweit bin ich mit der Lektüre noch nicht und da ggf. noch "verwöhnt" von VBA. Ich spreche mit

    VB.NET-Quellcode

    1. Dim LB As ListBox = frmAuswahlListbox.ListBox1

    Die ListBox in der Form "frmAuswahlListbox" an - die ist sozusagen als "Dialog-Form" angelegt und wird an mehreren Stellen im Programm benötigt.

    Wo ich gleich zu meiner nächsten Frage komme:

    Ich hab' mir ein Modul gebaut "allgemein", darin befindet sich ein Sub was den "Programmstart" abhandelt: User wird abgefragt, Ansicht wird festgelegt, Tree wird gefüllt etc.
    In dem Modul mache ich derzeit meine Public-Deklarationen, weil das Modul eben in jedem Fall mind. beim Programmstart einmal aufgerufen wird - womit wiederum gewährleistet ist dass
    die Variablen überall abgreifbar sind. Wie handhabt ihr das mit Public-Deklarationen?
    Wenn meine Vorgehensweise OK ist, dann könnte ich dort auch z.B. die Listbox aus frmAuswahlListbox als Objekt deklarieren und im weiteren Code damit einfacher weiterarbeiten.


    EDIT:
    Hab gerade mit einem Bekannten geredet, der zwar nicht direkt mit VB.NET arbeitet, aber bereits mit C und C++ gearbeitet hat.
    Uns hat sich die Frage gestellt, inwiefern die XML-Geschichte Mehrbenutzerfähig ist. Laut unseren Überlegungen nämlich eher schwierig, da das
    typisierte DataSet ja mit dem "Speicher" arbeitet und nicht direkt mit dem XML-Dateien. Folglich müsste man ja dauernd Abfragen starten, ob sich
    an den Files inzwischen was durch einen anderen Benutzer etc. geändert hat - das war meine Intention zu Anfang, direkt auf eine Datenbank zu gehen - die
    sind nämlich Mehrbenutzertauglich. Hier hab' ich allerdings das Problem, dass ich noch nicht mal die AccessDatabaseEngine auf den Rechnern installieren könnte,
    da die über die Domäne recht verriegelt sind was Installationen etc. anbelangt. Oder wird das für die Verbindung zu Access-Dateien garnicht benötigt? / Gibt es eine Alternative,
    (außer XML) wo nichts mit installiert werden muss?/Könnte man alles in die Anwendung mit reinpacken?

    Ist aber Zukunftsmusik, weshalb ich das erstmal auf XML-Basis durchprogrammiere und teste - alles für mich als alleinigen User.

    Danach müsste man sich dennoch mal Gedanken drum machen - oder bin ich hier auf dem Holzweg und XML kann das auch? :)
    "Na, wie ist das Wetter bei dir?"
    "Caps Lock."
    "Hä?"
    "Shift ohne Ende!" :thumbsup:

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

    tragl schrieb:

    Ist aber Zukunftsmusik, weshalb ich das erstmal auf XML-Basis durchprogrammiere und teste - alles für mich als alleinigen User.

    Danach müsste man sich dennoch mal Gedanken drum machen
    Naja, man kann späterhin das Xml durch eine Datenbank austauschen.

    Aber späterhin, wenns soweit fertig ist, dass du es als Einzelplatz-Anwendung nutzen könntest.
    Nicht vorher.



    Dein Admin-Tool sollteste als eigene Anwendung entwickeln, getrennt von dem, was du den Kollegen als Excel-Ersatz bereitstellen willst.



    Zu deine Modul-Geschichten hab ich mich ja schon abfällig geäussert.
    Bischen dachte ich, dir in meim Upload ja schon gezeigt zu haben, etwa wie Busynesslogik in die Dataset-Klasse gelandet ist und sowas.

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

    ErfinderDesRades schrieb:

    Aber späterhin, wenns soweit fertig ist, dass du es als Einzelplatz-Anwendung nutzen könntest.
    Nicht vorher.


    Ja dann machen wir das so.

    ErfinderDesRades schrieb:

    Dein Admin-Tool sollteste als eigene Anwendung entwickeln, getrennt von dem, was du den Kollegen als Excel-Ersatz bereitstellen willst.


    Ich persönlich sehe keinen Sinn darin, dass in eine extra-Anwendung zu packen. Möchte mich als "admin" einloggen und alles bearbeiten können, deshalb soll das schon mit darein :)

    ErfinderDesRades schrieb:

    Zu deine Modul-Geschichten hab ich mich ja schon abfällig geäussert.
    Bischen dachte ich, dir in meim Upload ja schon gezeigt zu haben, etwa wie Busynesslogik in die Dataset-Klasse gelandet ist und sowas.


    Das ist richtig und was oben zu sehen war / ist: das war nur ein Testcode, der auf den Button-Klick reagiert und der Code wird schon ordentlich verschoben / eingereiht. Wollte da erstmal grob testen ob das überhaupt
    so funzt, wie ich mir das gedacht hab.


    im Großen und Ganzen aber:
    Ich programmier das jetzt mit XML durch, mach mir pro Tabelle im DataSet ein eigenes GridView mit speichern / reload und wenn alles rennt wird das definitiv auf Datenbank umgebaut.
    Bis dahin mach ich mich schlau, was für eine Datenbank am einfachsten in unserer IT-Struktur einsetzbar ist, ohne den IT-Leuten auf den Schlips zu treten :)


    EDIT:
    Gibt es wenigstens die Möglichkeit, die Save und Reload-Buttons für das gesamte TabControl zu benutzen (also drunter setzen oder in ein MenuStrip) oder muss ich die für jede Tabelle separat anlegen?
    Bilder
    • unbenannt.png

      349,23 kB, 1.027×730, 147 mal angesehen
    "Na, wie ist das Wetter bei dir?"
    "Caps Lock."
    "Hä?"
    "Shift ohne Ende!" :thumbsup:

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

    tragl schrieb:

    Ich persönlich sehe keinen Sinn darin, dass in eine extra-Anwendung zu packen. Möchte mich als "admin" einloggen und alles bearbeiten können, deshalb soll das schon mit darein
    Hmm - vielleicht habich was falsch verstanden, was dir unter Admin-Tool vorschwebt.
    Ich verstand, du wollest damit beliebige Datasetse bearbeiten können - das heisst: Datenmodelle auch verschiedener Anwendungen.
    Das in eine dieser Anwendungen anzusiedeln scheint mir völlig verkehrt.

    Ansonsten ist die Programmier-Weise eines Admin-Tools auch diametral entgegengesetzt der Vorgehensweise einer Geschäfts-spezifischen Anwendung.
    Eine geschäfts-spezifische Anwendung hat ein definiertes Datenmodell, und präsentiert das in einer ergonomischen Oberfläche, die das Bearbeiten der Geschäftsvorfälle bestmöglich unterstützt.
    Und Fehleingaben sicher abwehrt.
    Sowas baut man auf einem typisierten Dataset auf.

    Ein Admin-Tool hat kein Datenmodell.
    Alle verfügbaren Daten sind mehr oder weniger beliebig abruf- und manipulier-bar - seien es Kunden-Bestellungen der einen Anwendung, Messwerte einer anderen, oder Mitarbeiter-Daten der dritten Anwendung.
    Jede Tabelle wird komplett und ungeschützt präsentiert - es gibt keine vorhersehbaren Geschäftsvorfälle, und jegliche Eingabe - auch solche, die den Datenbestand ruinieren können - sind zulässig.
    Ein Admin-Tool baut auf einem untypisierten Dataset auf, und man tut da genau all das, was man beim programmieren eines typisierten Datasets tunlichst unterlassen soll.
    Ich kann dir übrigens ein Admin-Tool schreiben - man kann das sehr einfach abhandeln.
    Dann isses abgehandelt, und du kannst dich "ordentlicher Programmierung" widmen.

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

    Es wird nur diese eine Anwendung geben - die darin enthaltenen Daten (bzw. die Daten die erstmal in der XML-Datei -> später in der Datenbank vorhanden sind)
    möchte ich gerne aus der gleichen Anwendung raus steuern. Wenn ich da wieder mit mehreren Anwendungen für bestimmte Programmteile anfange, dann kann ich auch
    gleich bei der Excel-Variante bleiben :)

    Hattest du meinen Edit für den Button oben noch gesehen? Ich möchte gerne die Save/Reload-Buttons einmalig in der "Verwaltungsform" haben, anstatt auf jeder TabPage für jede Tabelle/DGV
    ist das möglich (im typisierten Zugriff)?

    EDIT:
    Ich stehe auch vor dem nächsten Problem: es werden nicht mehrere Tabellen in die XML gespeichert. Wenn ich z.B. Einträge in "Ansicht" bearbeite dann werden die mit
    Klick auf "speichern" abgespeichert, bearbeite ich danach "Mitarbeiter" werden die DAten von "Ansicht" gelöscht und die von "Mitarbeiter" eingefügt.


    VB.NET-Quellcode

    1. Public Class frmEinstellungenDaten
    2. Private Sub btnSaveAnsicht_Click(sender As Object, e As EventArgs) Handles btnSaveAnsicht.Click
    3. Me.Validate()
    4. Me.DtsLogistik.Ansicht.WriteXml(DataFileUserdata.FullName)
    5. DtsLogistik.Ansicht.AcceptChanges()
    6. End Sub
    7. Private Sub btnSaveMitarbeiter_Click(sender As Object, e As EventArgs) Handles btnSaveMitarbeiter.Click
    8. Me.Validate()
    9. Me.DtsLogistik.Mitarbeiter.WriteXml(DataFileUserdata.FullName)
    10. DtsLogistik.Mitarbeiter.AcceptChanges()
    11. End Sub
    12. Private Sub btnUpdateAnsicht_Click(sender As Object, e As EventArgs) Handles btnUpdateAnsicht.Click, btnUpdateMitarbeiter.Click
    13. Me.DtsLogistik.reload()
    14. End Sub
    15. End Class


    VB.NET-Quellcode

    1. Partial Class dtsLogistik
    2. Public Sub reload()
    3. Me.Clear()
    4. If DataFileUserdata.Exists Then
    5. Me.ReadXml(DataFileUserdata.FullName)
    6. Else
    7. Msg_error($"DataFile{Lf}{DataFileUserdata.FullName}{Lf}not exists!")
    8. End If
    9. End Sub
    10. End Class 'dtsLogistik


    "Na, wie ist das Wetter bei dir?"
    "Caps Lock."
    "Hä?"
    "Shift ohne Ende!" :thumbsup:

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

    tragl schrieb:

    Es wird nur diese eine Anwendung geben - die darin enthaltenen Daten
    Ah - dann ist der Admin auch keine Wollmilchsau, sondern durchaus ans Geschäftsmodelll gebunden.
    Dann kann man den auch typisiert programmieren.
    guck dir mal die Solution von diesem Tut an:
    codeproject.com/Articles/10351…ped-Dataset-for-Beginners
    Was wir hier als "Admin-Bereich" bezeichnen, nenne ich sonst gerne "Stammdaten" (was auch nicht richtig ist), und im Tutorial nenne ich es den "Raw-View" (was auch nicht richtig ist).
    Jedenfalls ich mach für meine Tools immer (zuerst!!) eine TabPage, die alle Daten zeigt, und wo man viel verwüsten kann. Zuerst, weil dann kann ich schoma TestDaten anlegen.
    Aber dennoch ist das mit typisiertem Dataset gestaltet, und beinhaltet designete Views, und nicht nur platte Tabellen.
    Etwa die Bestellposten aller Bestellungen aller Kunden anzugucken macht auch für einen Admin keinen Sinn - da muss schon iwie ein View her, der was zusammenhängendes ausfiltert.

    Jo, und für diese meine "Stammdaten"-Tabpage ist natürlich durchaus sinnvoll, nicht jedem User zu präsentieren.



    Ansonsten musste dich mit formübergreifendem Databinding auseinandersetzen - genaugenommen mit "userControl-übergreifendem".
    Die Technik dazu ist im Tut auch enthalten - das ist die Geschichte mit der "Registrierung" des Datasets.



    tragl schrieb:

    es werden nicht mehrere Tabellen in die XML gespeichert. Wenn ich z.B. Einträge in "Ansicht" bearbeite dann werden die mit
    Klick auf "speichern" abgespeichert, bearbeite ich danach "Mitarbeiter" werden die DAten von "Ansicht" gelöscht und die von "Mitarbeiter" eingefügt.
    Was erwartest du?
    DataTable.WriteXml(fileName) schreibt eine Datei namens fileName mit den Daten der DataTable drinne.
    Wenn an der Stelle bereits eine annere Datei lag wird die wohl überschrieben.
    Mehrere Tabellen in eine Datei erhälst du mit Dataset.WriteXml.

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

    Das Tut sieht sehr interessant aus, werd ich auch mal durchackern. Ansonsten mit dem Speichern in die XML war natürlich ein blöder Fehler von mir ‍♂️ Und hätte ich auch selbst drauf kommen müssen.
    Das mit den RawViews ist so geplant und ist auch nur für mich bestimmt. Die anderen User erhalten abgesteckte Varianten davon (z.B. Kann ein Teamleiter dann seine Mitarbeiter „anlegen“ und zwar nur für seinen Standort etc.. über die RawViews will ich reagieren wenn einer Mist gebaut hat und da hab dann nur ich alleinigen Zugriff drauf, sonst keiner.

    Bin dann mal weiter das Buch lesen und evtl. heute Abend / heute Nacht noch das Tut
    "Na, wie ist das Wetter bei dir?"
    "Caps Lock."
    "Hä?"
    "Shift ohne Ende!" :thumbsup:
    So, hab meine "Verwaltungsform" nun lauffähig, ich kann alle Tabellen des DataSets bearbeiten und die Daten werden gespeichert.
    Ich hab sogar einige Dropdown-Boxen in das DGV eingebaut, wo die Daten aus anderen Tabellen ausgelesen werden (Relationen) usw.

    Im nächsten Schritt möchte ich mir eine ListView aus einer Tabelle des DataSets befüllen. (Ich weiß, es rät' mir jeder zu einem DGV aber ich find die ListView optisch ansprechender und
    in diesem Fall soll diese nur Daten aus einer Tabelle anzeigen und der User wählt via Doppelklick einen Eintrag aus - danach soll der ausgewählte Datensatz in Textboxen zum Editieren aufgeteilt werden).

    Ich hänge allerdings beim Befüllen der ListView. Die Spaltenbezeichnungen kann ich einwandfrei aus dem DS als Items auslesen, allerdings nicht als Spaltenkopf.
    Die Datensätze in der Tabelle werden auch nicht angezeigt...

    VB.NET-Quellcode

    1. Private Sub btnSuche_Click(sender As Object, e As EventArgs) Handles btnSuche.Click
    2. Dim lview As ListView = Me.ListView1
    3. Dim dsLog As New dtsLogistik
    4. dsLog.ReadXml(DataFileUserdata.FullName)
    5. 'Spaltennamen
    6. For i As Integer = 0 To dsLog.Mitarbeiter.Columns.Count - 1
    7. lview.Columns.Add(dsLog.Mitarbeiter.Columns(i).ColumnName)
    8. Debug_msg("Spalten", dsLog.Mitarbeiter.Columns(i).ColumnName)
    9. Next
    10. 'Zeilen
    11. For Each rw As DataRow In dsLog.Mitarbeiter.Rows
    12. lview.Items.Add(rw.ToString)
    13. Next
    14. End Sub


    Ich muss mir z.B. auch mit "dsLog.ReadXml" das DataSet neu befüllen, obwohl das bei Programmstart bereits erledigt wird:

    VB.NET-Quellcode

    1. Partial Class dtsLogistik
    2. Public Sub reload()
    3. Me.Clear()
    4. If DataFileUserdata.Exists Then
    5. Me.ReadXml(DataFileUserdata.FullName)
    6. Else
    7. Msg_error($"DataFile{Lf}{DataFileUserdata.FullName}{Lf}not exists!")
    8. End If
    9. End Sub
    10. Public Sub save(frm As Form)
    11. frm.Validate()
    12. Me.WriteXml(DataFileUserdata.FullName)
    13. Me.AcceptChanges()
    14. End Sub
    15. End Class 'dtsLogistik

    "Na, wie ist das Wetter bei dir?"
    "Caps Lock."
    "Hä?"
    "Shift ohne Ende!" :thumbsup:

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

    tragl schrieb:

    Ich weiß, es rät' mir jeder zu einem DGV aber ich find die ListView optisch ansprechender
    Mit wenigen Einstellungen kannst du die Optik eines DGVs so gestalten, dass nur ein ziemlich kundiger erkennt, dasses kein Listview ist.
    gugge noch ein coloriertes Datagridview

    (für besonders dickköpfige ist da auch sehr effizienter Code zum Befüllen eines ListViews gegeben - ich wollte beim Vergleich ja fair sein.)
    (Aber die Welt ist nunmal ein Nagel - warum sich mit Schraubenziehern abplagen, für was man auch mit dem Hammer erledigen kann? ;) )



    Ansonsten ist ein Denkfehler in deim Code:
    Auch eine Listview wird zur Designzeit mit Spalten ausgestattet - nicht zur Laufzeit.
    Sonst würde man ja bei jedem Befüllen immer mehr Spalten reinmachen.



    Ganz unerfindlich ist mir, warum du das Dataset, was du bereits befüllt hast, nochmal befüllen willst.
    Ist das befüllte Dataset, was du schon hast, nicht mehr gut, oder warum kannste dessen Daten nicht nehmen?
    Du musst nochmal das Code-Projekt-Tut lesen - vor allem das mit dem Highlander-Prinzip: Es kann nur einen geben!
    Nur ein Dataset!

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

    ErfinderDesRades schrieb:

    Ganz unerfindlich ist mir, warum du das Dataset, was du bereits befüllt hast, nochmal befüllen willst.


    Tja und genau das habe ich mich auch schon gefragt.
    Mal abgesehen davon, dass ich ja keine Einträge im ListView angezeigt bekomme (wegen dem Denkfehler oder was auch immer - kümmer' ich mich nachher drum),
    hatte ich mir Testweise die Anzahl der Rows aus der besagten Tabelle des DataSet in einer Messagebox ausgeben lassen. Die war leider 0, obwohl 1 Eintrag testweise
    vorhanden ist. Befülle ich das neu, wird mir auch 1 angezeigt.

    Hier fehlt mir vermutlich noch was an Wissen, denn:
    Spreche ich die Tabelle direkt an wie z.B. hier

    funktioniert:

    VB.NET-Quellcode

    1. Dim filteredSorted = Tree.Select


    in meiner anderen Form funktioniert das nicht - es wird mir angezeigt "Der Verweis auf einen nicht freigegebenen Member erfordert einen Objektverweis"
    "Imports.Logistik_Tool.dtsLogistik" habe ich oben angefügt:

    VB.NET-Quellcode

    1. Mitarbeiter.Select


    deshalb bin ich den Weg gegangen mit

    VB.NET-Quellcode

    1. Dim dsLog As New dtsLogistik


    womit vermutlich ein "leeres neues" DataSet erzeugt wird, was wiederum erst befüllt werden muss.
    Wie gesagt - vermutlich Verständnisfehler, kommt bestimmt auch noch im Buch. Ich acker' dann mal den nächsten
    Thread "noch ein coloriertes Dataset" durch :)

    EDIT: Auch mit dem Datagridview muss ich erst das DS befüllen und vor Allem erst das DataSet aus der Toolbox auf die Form ziehen, damit
    ich da ordentlich drauf zugreifen kann (siehe Bild)

    VB.NET-Quellcode

    1. Private Sub btnSuche_Click(sender As Object, e As EventArgs) Handles btnSuche.Click
    2. DtsLogistik1.reload()
    3. Me.DataGridView1.DataSource = DtsLogistik1.Mitarbeiter
    4. Me.DataGridView1.Columns(DtsLogistik1.Mitarbeiter.IDColumn.ToString).Visible = False
    5. End Sub
    Bilder
    • unbenannt.png

      349,23 kB, 1.503×1.647, 130 mal angesehen
    "Na, wie ist das Wetter bei dir?"
    "Caps Lock."
    "Hä?"
    "Shift ohne Ende!" :thumbsup:

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

    tragl schrieb:

    in meiner anderen Form funktioniert das nicht
    Der Wortlaut des CompileFehlers bedeutet, dass eine Klasse, also ein Datentyp als Objekt versucht wird anzusprechen (diese Verwechslungsgefahr rührt an dieser Stelle letztlich vonne Imports-Anweisung her).
    Tree.Select, Mitarbeiter.Select kann nur innerhalb des typDatasets funktionieren (weil dann quasi das Schlüsselwort Me unsichtbar vorangestellt wird).
    Wäre glaub besser zu schreiben Me.Tree.Select, Me.Mitarbeiter.Select.
    Wenn Me die partiale Dataset-Klasse ist, funzt das, denn das Dataset hat eine Property Tree.
    Ist Me ein Form funzt das natürlich nicht, denn ein Form hat diese Property nicht (und probier nicht, eine hinzumachen - dann blickt keiner mehr durch).

    Zu alldem steht im Buch nix - das sind keine Grundlagen mehr.
    Doch - das Schlüsselwort Me - dazu müsste's was geben. Ansonsten gucken auf Schlüsselworte.



    Ansonsten - wo du nu mit mehreren Forms hantierst, hast du "Formübergreifendem Databinding" am Hals.
    Die Lösung ist kompliziert, aber ist im englischen Tut enthalten, und im DatasetOnly-Tut auch.
    Dieselben Daten mehrmals in dieselbe Anwendung laden ist nicht die Lösung.
    Sondern was Onkel Highlander uns kompromittiert.

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

    Ok, dann war ich ja doch nicht so ganz auf dem Holzweg.
    Aber wie bekomme ich das nun hin, dass ich das DataSet von überall in der Anwendung aus ansprechen kann ohne mir davon "kopien (in form von dts1, dts2 etc.)" basteln zu müssen?
    Ich hab' mir schon gedacht dass das nicht die elegante Lösung ist....

    In dem DataSetOnly-Tut hab ich auf Anhieb nix dazu gefunden, das englische muss ich mir dann mal durchlesen.
    "Na, wie ist das Wetter bei dir?"
    "Caps Lock."
    "Hä?"
    "Shift ohne Ende!" :thumbsup:

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

    ErfinderDesRades schrieb:

    sorry - ich hab 2 ähnliche Tuts verzapft, die ich nu gelegentlich verwelchser.



    Ok, ich denke das hab' ich verstanden - auch wenn ich das einfacher gefunden hätte, wenn das DataSet Projektweit zur Verfügung stände.
    Was wäre denn, wenn ich zu der Table noch nirgends eine BindingSource gehabt hätte?

    Ansonsten zeigt mit das DGV nun mit Klick die Daten aus der BindingSource der anderen Form an.
    Allerdings will er mir absolut die Filterfunktion nicht ausführen... eine Idee? (Ich hatte das abgewandelt aus deiner Tree-Filter-Funktion übernommen)

    VB.NET-Quellcode

    1. Dim suchSpalte As DataColumn
    2. Dim suchBegriff As String = Me.TbSuche.Text
    3. Dim inaktiv As CheckState = Me.CbInaktiv.CheckState
    4. Dim ds As dtsLogistik = frmEinstellungenDaten.DtsLogistik
    5. Dim tb As MitarbeiterDataTable = ds.Mitarbeiter
    6. If Not suchBegriff = "" Then
    7. Select Case True
    8. Case rbtnName.Checked
    9. suchSpalte = tb.NameVornameColumn
    10. Case rbtnStandort.Checked
    11. suchSpalte = tb.Standort_1Column
    12. Case rbtnFunktion.Checked
    13. suchSpalte = tb.FunktionColumn
    14. Case Else
    15. suchSpalte = tb.NameVornameColumn
    16. End Select
    17. Dim filtered As List(Of DataRow)
    18. If inaktiv = CheckState.Checked Then
    19. filtered = tb.Select($"{suchSpalte} = {suchBegriff} AND Aktiv = False").ToList
    20. Else
    21. filtered = tb.Select($"{suchSpalte} = {suchBegriff} AND Aktiv = True").ToList
    22. End If
    23. Me.DataGridView1.DataSource = filtered
    24. Else
    25. Me.DataGridView1.DataSource = tb
    26. End If
    27. Me.DataGridView1.Columns(tb.IDColumn.ToString).Visible = False
    28. End Sub


    Mit und ohne '-Zeichen bei suchBegriff probiert
    Bilder
    • unbenannt.png

      349,23 kB, 1.549×258, 121 mal angesehen
    "Na, wie ist das Wetter bei dir?"
    "Caps Lock."
    "Hä?"
    "Shift ohne Ende!" :thumbsup:

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

    deine Fragen verstehe ich nicht.

    tragl schrieb:

    [...] auch wenn ich das einfacher gefunden hätte, wenn das DataSet Projektweit zur Verfügung stände.
    Jo - fände ich auch besser.

    tragl schrieb:

    Was wäre denn, wenn ich zu der Table noch nirgends eine BindingSource gehabt hätte?
    Ja - was soll dann sein?

    Aber dein Bildle kann ich glaub erklären: Vermutlich steht in suchString 1, und das ergibt iwie keinen Sinn.
    nee, vielleicht auch nicht.
    Am besten du bastelst eine ZwischenVariable, dass wirklich klar ist, was als Expression dem .Select() übergeben wird.

    VB.NET-Quellcode

    1. dim expression = $"{suchSpalte} = {suchBegriff} AND Aktiv = False"
    2. filtered = tb.Select(expression).ToList
    Aber das ist ja auch wieder mumpitz - dein Bildle zeigt anderen Code als dein Code-Snippet - also ich versteh nu garnix.

    Versuchs nochmal, und mit genau einer Frage.
    Sorry, ich hatte den Code zwischenzeitig geändert - daher waren Bild und Code unterschiedlich.
    Hier mal aktuell - bitte gib' mir auch mal Rückinfo, ob ich das mit dem DataSet nun korrekt handhabe :)
    Also setze ich keinen Filter, läuft das sauber durch und zeigt mir alle Daten aus der Table an. Mit Filter erhalte ich die Meldung (siehe Bild):

    VB.NET-Quellcode

    1. Dim suchSpalte As DataColumn
    2. Dim suchBegriff As String = Me.TbSuche.Text
    3. Dim inaktiv As CheckState = Me.CbInaktiv.CheckState
    4. Dim ds As dtsLogistik = frmEinstellungenDaten.DtsLogistik
    5. Dim tb As MitarbeiterDataTable = ds.Mitarbeiter
    6. If Not suchBegriff = "" Then
    7. Select Case True
    8. Case rbtnName.Checked
    9. suchSpalte = tb.NameVornameColumn
    10. Case rbtnStandort.Checked
    11. suchSpalte = tb.Standort_1Column
    12. Case rbtnFunktion.Checked
    13. suchSpalte = tb.FunktionColumn
    14. Case Else
    15. suchSpalte = tb.NameVornameColumn
    16. End Select
    17. Dim filtered As List(Of DataRow)
    18. Dim expression As String = Nothing
    19. If inaktiv = CheckState.Checked Then
    20. expression = $"{suchSpalte} = {suchBegriff}"
    21. Else
    22. expression = $"{suchSpalte} = {suchBegriff} AND Aktiv = True"
    23. End If
    24. filtered = tb.Select(expression).ToList
    25. Me.DataGridView1.DataSource = filtered
    26. Else
    27. Me.DataGridView1.DataSource = tb
    28. End If
    29. Me.DataGridView1.Columns(tb.IDColumn.ToString).Visible = False
    30. End Sub
    Bilder
    • unbenannt.png

      349,23 kB, 1.306×886, 123 mal angesehen
    "Na, wie ist das Wetter bei dir?"
    "Caps Lock."
    "Hä?"
    "Shift ohne Ende!" :thumbsup: