DataSet only - Datarow kopieren, mit Form und möglichen Useränderungen

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

Es gibt 33 Antworten in diesem Thema. Der letzte Beitrag () ist von VB1963.

    DataSet only - Datarow kopieren, mit Form und möglichen Useränderungen

    Hallo hallo
    Ich bastel gerade an einer Artikelverwaltung.
    Dazu habe ich ein DataSet mit entsprechendem DataTable erstellt und lasse mir meine Artikel in einem Dgv anzeigen.
    Zum "neuen Artikel anlegen" und Artikel ändern, nutze ich die Helpers von @ErfinderDesRades
    Also "ArticleBindingSource.EditNew" und "ArticleBindingSource.EditCurrent"
    Die hierfür angelegte Form, möchte ich nun nutzen um auch eine kopieren Funktion zu erstellen.
    Also quasi ein .EditNew, welches mir aber die Daten der aktuell ausgewählten DataRow in meinem Detailview der Form anzeigt.
    Gibt es hierzu auch eine Funktion in den Helpers, die ich nicht finde?
    Wird den dir mit .EditNew keine neue Row angelegt?
    Zitat von @ErfinderDesRades :
    'Das Detail-Form muß natürlich geeignet sein, also es muß son Dataset aufweisen, und mindestens einen Ok-Button, der das Form mit DialogResult.Ok schließt.'

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

    @VB1963: Doch, nur der TE sucht ne Funktion/Überladung, die eben ne bestehende Row als Datenvorlage für ne neue Row hernimmt.
    @DerSmurf: Hab auch nix gefunden.
    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
    Genau das suche ich.
    Schade, dann macht es ja wahrscheinlich mehr Sinn in diesem Fall alles ohne die Helpers zu erledigen, damit ich alle 3 Funktionen (kopieren, editieren, neu anlegen) problemlos mit der gleichen Form erledigen kann.
    Musst Du selber entscheiden. Ansonsten erweiterst Du die Helpers selber, sind ja OpenSource
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    Doch, da gibts eine dafür vorgesehene Überladung:

    VB.NET-Quellcode

    1. ''' <summary> editiert bs.AddNew im angegebenen Dialog-Form. </summary>
    2. <Extension()> _
    3. Public Function EditNew(Of T As {Form, New})(bs As BindingSource, defaultValues As List(Of Tuple(Of DataColumn, Object)), Optional owner As Form = Nothing, Optional onErrorRetry As Boolean = False) As DialogResult
    4. Dim drv = DirectCast(bs.AddNew, DataRowView)
    5. defaultValues.ForEach(Sub(tpl) drv(tpl.Item1.ColumnName) = tpl.Item2)
    6. Return EditItem(Of T)(bs, drv, onErrorRetry, owner)
    7. End Function
    Hier kannste mittels einer TupleList angeben, welhe Spalten mit welchen Werten vorbelegt sein sollen.
    Ich gabs zu, ist bischen umständlich, v.a. wenn man meine TupleList nicht kennt.
    Aber kannste ja kennenlernen ;)

    DerSmurf schrieb:

    und dann anch dieser komischen Tulpe googlen.
    Zu Tuple gibts nicht soo viel zu googeln finde ich - ObjectBrowser sagt dir eiglich schon alles.
    Spannender ist, was ich damit in meiner TupleList verzapfe - da weiss Google aber nix von (zumindest verraten sie nicht, was sie darüber wissen)).

    Also wenn du mir ein Beispiel-Problem zur Verfügung stellst, könnte ich eine BeispielLösung dranbasteln.
    Also ieine Anwendung, wo du mit EditNew arbeitest, aber bestimmte Vorbelegungen im EditDialog haben möchtest (und welche).
    @ErfinderDesRades
    Ich habe mal schnell das Demoprojekt mit dem entsprechenden DateSet geschustert.
    Eine Formatierung der ganzen Controls usw. habe ich mir mal gespart, die Schrift habe ich nur etwas vergrößert, damit ich da auch was erkennen kann...

    Beim kopieren in der frmEditArticle soll die Artikelnummer um eins erhöht werden (sofern diese denn auf eine Zahl endet, wenn nicht soll ne 1 rangeklatscht werden. Diese Bedingung kann ich aber auch einfügen)
    Folgende Textboxen sollen NICHT vorbelegt sein (alle anderen sollen dann entsprechend eine Vorbelegung erhalten)
    EAN / LastCalculation / OldPurchasingPrice

    Ich möchte aber ChangeEvents für folgende Textboxen einfügen: ListPrice, Discount, PurchasingPrice, SalesMargin, RetailPrice.
    Wenn sich hier etwas ändert, soll sich der Wert in einer vom geänderten Wert abhngigen Textbox ändern.
    Ändere ich also z.B. den Wert in der Textbox SalesMargin, soll sich der RetailPrice ändern (errechnet aus PurchasingPrice und SalesMargin)
    Nur falls das für die Tuple eine Rolle spielt.

    Außerdem möchte ich den OK Button noch mit einer Funktion belegen (hoffe dass das überhaupt möglich ist), die mir bei einer Änderung des PurchasingPrice, die Felder LastCalculation und OldPurchasingPrice entsprechend befüllt.
    Dateien

    DerSmurf schrieb:

    Beim kopieren in der frmEditArticle
    Was meinst du mit "Kopieren"?
    Was soll wohin kopiert werden?

    .

    DerSmurf schrieb:

    (alle anderen sollen dann entsprechend eine Vorbelegung erhalten)
    Welche Vorbelegung sollen sie erhalten?
    Ich klatsche mal einfach "42" rein.
    Dateien

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

    Ups.
    Bitte entschuldige meine "NichtInfos".
    Mit "kopieren" meine ich den aktuell ausgewählten Artikel.
    Also quase ein EditNew, wo in der Form die Werte des aktuell ausgewählten Artikels in den Textboxen stehen.
    Dabei sollte der Neu Button einen neuen Eintrag anlegen (EditNew)
    der bearbeiten Button soll den aktuell ausgewählten Artikel editierbar machen (EditCurrent)
    und der kopieren Button soll ein EditNew(Of frmEditArticle)(tlps) sein

    Aber hier muss ich ja jetzt nur deinen Dim tlps ... Code anpassen und mit den Werten aus der BindingSource.Current füllen.
    Dieses komische doppelgecaste.
    Und ggf. die übergebenen Werte ändern. Das bekomm ich mit deiner Vorlage hin :)

    edit: im Link den @Dksksm gepostet hat steht, das Tuple die Net Version 4.7 erfordert.
    Wenn ich in meiner Demo hier das Framework von 4.5 auf 4.7.2 hochschraube, bekomme ich trotzdem den Fehler, dass die Tuple ein unbekannter Typ ist.
    In deinem Projekt @ErfinderDesRades ist die Net Version aber 4.6.1, das habe ich nicht installiert, deswegen 4.6 draus gemacht, gehts aber wunderbar. Das liegt ja denke ich an deinen anderen Projekten in der Mappe.
    Kannst du mir noch verraten, auf welche DLL ich zusätzlich zu den "HelpersSmallEd" noch einen Verweis setzen muss, damit meine Tulpe blüht?
    Vielen Dank!

    Aber eine Sache macht mich gerade doch etwas stutzig.
    Die Combobox Supplier. Mit dieser möchte ich einen Artikel einem Lieferanten zuordnen.
    Dafür habe ich im DataSet zwei DataTable angelegt. "Article" und "Supplier"
    Supplier hat nur die Spalten ID und Name und in Article gibt es eine SupplierID - diese haben die entsprechende Beziehung.
    Wenn mittels Combobox ein Lieferant angegeben wird, den es nicht gibt, soll er angelegt werden.
    Ich bin mir ziemlich sicher, dass meine Combobox Einstellungen korrekt sind:
    Datenquelle: SupplierBindingSouce
    Member anzeigen: Name
    WerteMember: ID
    Ausgewählter Wert: ArticleBindingSource - SupplierID
    aber es wird kein neuer Lieferant angelegt, wenn ich in die Combobox etwas eintippe. Der Wert ist nach Klick auf den OK Button "einfach weg"

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

    Ich wag ja mal zu behaupten, dass das Anlegen eines komplexen Objekts nur über die Eingabe eines Textes in einer ComboBox nicht möglich ist. Man könnte natürlich sagen: Ich lege in der entsprechenden SupplierTable Default-Werte an. Aber spätestens, wenn der Konstruktor eine ParentRow will, geht's ja gar nicht. Man könnte das Row-Neuanlegen bestimmt über das KeyDown-Event der ComboBox handeln, aber sonst wird - denke ich - kein sinnvolles Event ausgelöst, wenn man etwas in die ComboBox eingibt, was noch nicht als Eintrag vorhanden ist.
    (btw: Ihr könnt das zwar so handhaben wie Ihr wollt, aber das heißt m.E. nicht Article, sondern Item. Article bezieht sich im Englischen auf z.B. Zeitungsartikel oder Einzelteil/Bestandteil, aber bei (ganzen) Gegenständen verwendet man m.E. Item.)
    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.
    Ja. Item macht glaube ich tatsächlich mehr Sinn...

    Wenn eine automatische Erstellung des Lieferanten nicht geht, kann ich doch auch dem speichern Button eine sub schenken, die supplierbindingsource.current prüft.
    Wenn nothing dann neue row in supplier anlegen, id mit demdoppelcast Gedöns (wie heißt das eigentlich richtig) herausfinden und diese in article.SupplierID speichern.

    DerSmurf schrieb:

    Wenn nothing dann neue row in supplier anlegen
    Wie ich schon mal erwähnte: Solange was in ner gebundenen Liste drinsteht und angezeigt wird, ist es mir bisher nicht gelungen, Current Nothing werden zu lassen bzw. für Position -1 festzulegen. Das ist also m.E. kein gangbarer Weg. Ich würde an Deiner Stelle - theoretisch, da ich diesen Weg nicht gehe - beim KeyDown-EventHandler den eingegebenen Text auswerten und wenn der eben nicht bei den Suppliernamen dabei ist, erstmal den Benutzer fragen, ob ein neuer Supplier angelegt werden soll (nicht, dass man sich vertippt hat) und dann erst einen neuen anlegen.
    Wie Dksksm bereits erwähnte, gibt es für höhere Frameworkklassen auch die einfacheren Tuples, die dann z.B. so verwendet werden (können)

    VB.NET-Quellcode

    1. Private Sub TestTupleCreation()
    2. Dim MyComplexData = (Text:="foo", Number:=1, Date.Now)
    3. MessageBox.Show(MyComplexData.Text) 'foo
    4. MyComplexData.Text = "bar"
    5. MessageBox.Show(MyComplexData.Text) 'bar
    6. Dim Result = GetAnotherTuple()
    7. MessageBox.Show(Result.Temperature.ToString) '39.7
    8. MessageBox.Show(Result.Flag.ToString) 'true
    9. End Sub
    10. Public Function GetAnotherTuple() As (Flag As Boolean, Temperature As Double)
    11. Return (True, 39.7)
    12. End Function


    ##########

    Gelogen. Natürlich kann man eine BindingSource auch bei bestehender Liste mit einem einfachen Trick veranlassen, Current auf Nothing bzw. Position auf -1 zu bekommen. Da man ja optimalerweise in jeder DataTable eine ID-Spalte hat, kann man natürlich einfach den BS-Filter entsprechend so setzen, dass nix angezeigt wird, also bei den default-ID-Einstellungen, bei denen ID bei -1 anfängt und dann immer weiter um 1 gesenkt wird, stellt man einfach mal ein: DeineBindingSource.Filter = "ID=0". Aber ohne solche Tricks bekommt man eben aus einer ComboBox durch normale Auswahl/Eingabe kein Nothing/-1 für die entsprechenden Properties zurückgeliefert.
    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“ ()

    @Dksksm
    Ja, aber ich übergebe ja keine Tuple, sondern eine List(of Tuples)

    VB.NET-Quellcode

    1. Private Sub BTNCopyArticle_Click(sender As Object, e As EventArgs) Handles BTNCopyArticle.Click
    2. With Articles.Article
    3. Dim tpls = TupleList.From(.ArtNrColumn, CObj("lkj"))(.EANColumn, 42)(.Name1Column, "Name1")(.Name2Column, "Name2")(.VeColumn, 42)
    4. ArticleBindingSource.EditNew(Of frmEditArticle)(tpls)
    5. End With
    6. End Sub

    Ich habe nun den Verweis auf meine eingebundene HelpersSmallEd entfernt (denn das unterstütz scheinbar die Übergabe der Tuple noch nicht) und die beiden dlls aus dem Demoprojekt vom @ErfinderDesRades eingebunden.
    Die GeneralHelpersVB brauche ich scheinbar für die Funktionaltät wie EditCurrent und EditNew.
    Die WinformHelpers brauche ich für die Erstellung der TupleList Dim tpls = TupleList.From

    Nun ist ja aber diese Übergabe eine Sache die ich nur einmal brauche.
    Da Frage ich mich dann als Vb.Net Neuling ob da ein solcher Import Sinn macht.
    Oder ob es dann sinnvoller ist die Funktionalität (Neu anlegen, ändern, vorhandenen Artikel kopieren=Neu mit eingetragenen Werten des ausgewählten Artikels) selber zu erstellen, um um diesen Import herumzukommen.
    Edit: also in dem Import befindet sich ja auch ein haufen Code, den ich nicht brauche.
    Ist so etwas nicht irgendwie zu vermeiden? Oder ist das einfach wurscht.
    Oder könnte ich mir zum Beispiel auch den Code, den ich aus den Helpers brauche rauspulen und als Klasse in mein Projekt einfügen, oder sowas in der Art? Einfach um das ganze kleiner zu halten - weil ich ja dann nur den Code habe den ich auch brauche.


    Also ich könnte ja zum Beispiel auch die Werte, welche ich beim kopieren in den Textboxen der Form haben möchte, aus der BindingSource auslesen und als Parameter an die neue Form übergeben, oder sowas in der Art.
    Edit: Nein kann ich mit EditNew nicht...

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

    DerSmurf schrieb:

    in dem Import befindet sich ja auch ein haufen Code, den ich nicht brauche. Ist so etwas nicht irgendwie zu vermeiden?
    Bei jedem (DLL-)Import hast Du tonnenweise Code, den Du normalerweise nicht brauchst. Normalerweise importiert man ja ne (vor)kompilierte Bibliothek. Und das ist wie bei ner echten Bibliothek. Nur weil dort 10000 Bücher zur Verfügung stehen, heißt das ja nicht, dass man auch alle lesen/verwenden muss.

    DerSmurf schrieb:

    Oder könnte ich mir zum Beispiel auch den Code, den ich aus den Helpers brauche rauspulen und als Klasse in mein Projekt einfügen
    Kannst Du. Ob Du darfst, musst Du den Autor fragen. Musst nur aufpassen, dass alle Abhängigkeiten drin sind, sonst funktioniert es eben nicht.
    Wie das jetzt mit EditNew funktioniert, wird Dir EdR bestimmt bald schreiben. Er hat's ja in Post#9 angeboten.

    DerSmurf schrieb:

    Also ich könnte ja zum Beispiel auch die Werte, welche ich beim kopieren in den Textboxen der Form haben möchte, aus der BindingSource auslesen und als Parameter an die neue Form übergeben, oder sowas in der Art.
    Geht auch. Dann machst Du eben alles wieder zu Fuß. Ist immer eine Frage: Rad neu erfinden und dann unabhängig von fremdem Code* sein, aber dann eben Gefahr laufen, dass man suboptimale Lösungen in einer Zeit erschafft, die man auch anders hätte investieren können. Oder eben auf bestehende Konstrukte bauen, von denen man dann immer abhängig ist.

    * das .Net-Framework ist auch fremder Code. Und ohne den geht ja eigentlich kaum was. Von daher: komplette Unabhängigkeit ist eh Illusion. Zumindest für den normalsterblichen Programmierer.
    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.
    Danke für die Ausführung.

    Die Abhängigkeit stört mich kein bisschen und generell macht es ja aus meiner Sinn deutlich mehr Sinn, den vorgefertigten Code von @ErfinderDesRades, statt meines eigenen zu verwenden.
    Denn der Kerl weiß ja was er tut (im Gegensatz zu mir) und das was ich so fabrizieren kann (zumindest zur Zeit noch) ist ja "ein Dreck" im Gegensatz zu dem, was ein erfahrener Programmierer - der sich wahrscheinlich schon seid Jahren intensiv mit dem Problem beschäftigt - dahin schreibt.

    Wenn ich dich also richtig verstehe ist der "überflüssige" Code - also alles was ich importiere, aber nie verwende, überhaupt gar nicht tragisch.
    Der einzige "Nachteil" ist, dass ich zwei dlls einbinde, die zusammen 350Kb groß sind, obwohl sie eigentlich nur 50Kb (natürlich geraten) groß sein müssten.
    Alle Subs in den dlls, die ich nicht brauche, stören mein Programm nicht?

    Edit:
    Also stelle dir vor ich nehme mir die beiden imports meines Programmes und bastel mir daraus eine dll, die nur den Code enthält den ich auch brauche.
    Es macht dann in der Programmausführung keinen Unterschied, ob ich die beiden dlls mit allem, oder nur "meine" dll importiere?