Erweiterter Umgang mit typisiertem DataSet -> Tabellennamen lesen/Namensübergabe etc.
- VB.NET
- .NET (FX) 4.0
Sie verwenden einen veralteten Browser (%browser%) mit Sicherheitsschwachstellen und können nicht alle Funktionen dieser Webseite nutzen.
Hier erfahren Sie, wie einfach Sie Ihren Browser aktualisieren können.
Hier erfahren Sie, wie einfach Sie Ihren Browser aktualisieren können.
Es gibt 351 Antworten in diesem Thema. Der letzte Beitrag () ist von tragl.
-
-
"Na, wie ist das Wetter bei dir?"
"Caps Lock."
"Hä?"
"Shift ohne Ende!" -
@ErfinderDesRades:
Hast du noch eine Lösung für mein Problem mit dem Filtern?
Das DGV reagiert leider nicht auf die Filter der BS, die nicht an's DGV gebunden sind..
An einem kleinen Beispiel:
Tabelle Mitarbeiter hat folgende Spalten:
ID
Name
Adresse
StandortID -> FK aus Tabelle Standort (FK_Standort_Mitarbeiter)
Ich kann nun problemlos die Mitarbeiter filtern mit:
bsMitarbeiter.Filter = "Name Like *Mustermann*"
bsMitarbeiter.FIlter = "Adresse Like *Musterstadt*"
Was jedoch nicht geht ist:
bsMitarbeiter.Filter = "StandortID Like *Standortname*"
denn hier werden ja nur die StandortID's benutzt. Kann ich das regeln, OHNE eine Spalte für den Standortnamen in die Mitarbeiter-Table zu packen?
tragl schrieb:
Nochmal zum Thema gefilterte Anzeige der Daten in einem DGV. Im Beispiel
2.2 Datenabfrage HC - dort hab ich ja über dem DGV allerhand Filtermöglichkeiten vorgesehen.
Jetzt ist es so, dass sich die Filter eigentlich alle auf unterschiedliche BindingSources beziehen:
-Datum: ist in der eigentlichen bsDatenabfrageHc vorhanden
-Mitarbeiter: kommt aus der bsCbcMitarbeiter / in bsDatenabfrageHc gibt's nur MitarbeiterID - nicht den Namen aus [Mitarbeiter].expFullname der für den Filter verwendet werden soll
-Fahrzeug: kommt aus der bsCbcFahrzeug / in bsDatenabfrageHc gibt's nur FahrzeugID - nicht das Kennzeichen aus [Fahrzeug].Kennzeichen was für den Filter verwendet werden soll
-Standort: hier hab ich gar keinen Ansatz / die StandortID ist unter [Mitarbeiter].StandortID hinterlegt
Der Code zum Filtern ist aktuell wie folgt:
VB.NET-Quellcode
Private Sub btn_Click(sender As Object, e As EventArgs) Handles btnAusgabe.Click
Select Case True
Case sender Is btnAusgabe
Dim strFilter As String = Nothing
If CbDatum.Checked = True Then
bsDatenabfrageHc.FilterX("Datum >= ? AND Datum <= ?", dtpVon.Value, dtpBis.Value)
Else
bsDatenabfrageHc.Filter = ""
End If
If CbMitarbeiter.Checked = True Then
bsCbcMitarbeiter.FilterX("expFullname Like *?*", TbMitarbeiter.Text)
Else
bsCbcMitarbeiter.Filter = ""
End If
If CbFahrzeug.Checked = True Then
bsCbcFahrzeug.FilterX("Kennzeichen Like *?*", TbFahrzeug.Text)
Else
bsCbcFahrzeug.Filter = ""
End If
If CbStandort.Checked = True Then
'???
End If
End Select
End Sub
Beim Datum versucht er zumindest zu filtern, allerdings zeigt er mir mit Beispiel von 16.04.2020 bis 16.04.2020 nix an, obwoh Einträge
mit dem Datum vorhanden sind. Beim Filtern von z.B. Mitarbeitern passiert garnix.
Ich hoff' ich konnte das verständlich rüberbringen - du hast ja meine Version da, zum Angucken jedoch ohne den neuen "FilterCode"
Komplexer Kram. Aber ich merke Tag für Tag mehr, dass du mit dem DataSet und der XML-Geschichte Recht hattest - eine Datenbank zum
jetzigen Zeitpunkt hätte mich vermutlich in den Wahnsinn getrieben. Wenn "Mehrbenutzer" über XML möglich ist, würde ich die Variante
vermutlich sogar so belassen ohne Datenbank."Na, wie ist das Wetter bei dir?"
"Caps Lock."
"Hä?"
"Shift ohne Ende!" -
-
ErfinderDesRades schrieb:
probierma
VB.NET-Quellcode
bsMitarbeiter.Filter = "Parent(FK_MitarbeiterStandort).StandortName Like '*Standortname*'"
Jou, da hätt' ich auch drauf kommen sollen - geht natürlich.
Also ich hab's mit dem Mitarbeiternamen probiertbsDatenabfrageHc.FilterX("Parent(FK_Mitarbeiter_DatenabfrageHc).expFullname LIKE *?*", TbMitarbeiter.Text)
ABER:
wie filter ich jetzt den Standort? Die StandortID ist in Tabelle Mitarbeiter hinterlegt, die Tabelle mitarbeiter ist mit FK_Mitarbeiter_DatenabfrageHc
mit der Datenabfrage verbunden, Standort jedoch nicht.
Die Relation Standort->Mitarbeiter (ID->StandortID) lautet "FK_Standort_Mitarbeiter". Kann ich die Relationen im Filter verschachteln oder wie komm ich am besten an den Standortnamen?
"Na, wie ist das Wetter bei dir?"
"Caps Lock."
"Hä?"
"Shift ohne Ende!"Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „tragl“ ()
-
Mehr als eine Ebene kannste dich in Expressions nicht hoch-tricksen.
Wenn ich recht verstanden habe, was du wolle.
Weil wirklich Frage verstanden " wie komm ich am besten an den Standortnamen?" habich nicht. Obiges Snippet kann man doch grad so verstehen, dass du da an den StandortNamen kommst - was ist damit nicht in Ordnung?
Man könnte was irrwitziges mit OwnerDrawing basteln, mit dem man in ungebundenen DGV-Zellen beliebig wüst verknüpfte Werte anzeigen kann.
Aber würde viel Arbeit machen.
Oder einfacher wärs mittm CellFormatting-Event. Aber bleibt immer der Aufwand Code zu schreiben, der sagt, was wann wo angezeigt wern soll. -
ErfinderDesRades schrieb:
Weil wirklich Frage verstanden " wie komm ich am besten an den Standortnamen?" habich nicht. Obiges Snippet kann man doch grad so verstehen, dass du da an den StandortNamen kommst - was ist damit nicht in Ordnung?
Naja, ich arbeite ja in der Tabelle "DatenabfrageHc" mit den Filtern.
Tabelle Mitarbeiter und Fahrzeug sind übergeordnet, sodass ich mir "Kennzeichen" und "expFullname" filtern kann.
Tabelle Standort ist aber nicht direkt übergeordnet zu DatenabfrageHc sondern zu Mitarbeiter.
Ich möchte am Ende ja folgendes Filtern:
Datumsbereich
ggf. einzelne Mitarbeiter
ggf. einzelne Fahrzeuge
ggf. komplette Standorte (welcher den Mitarbeitern zugeordnet ist)
Ich möchte also die Möglichkeit haben, mir alle Eingaben in DatenabfrageHc anzeigen zu lassen, welche z.B. die Mitarbeiter aus "Standort1" betrifft
und das scheint mir mit der aktuellen Konstellation unmöglich zu sein.
Würde ich jetzt noch das Feld "Standortname" der Mitarbeitertabelle zufügen, dann wär's kein Problem - ich glaub das werd' ich auch machen, am Ende wird es
keine Rolle spielen ob "StandortID" oder "Standortname" in der Mitarbeitertabelle drin steht oder? Ich hoffe du kommst noch mit
nochwas anneres:
Ich hab deiner ControlStyling noch folgendes hinzugefügt:
Allerdings macht er kein AutoComplete an den ComboBoxen. Hab ich was falsch gemacht? Stell ich das manuell an den Boxen ein geht das."Na, wie ist das Wetter bei dir?"
"Caps Lock."
"Hä?"
"Shift ohne Ende!" -
Sieht mir sehr falsch aus. Aber ich sag nicht vor, sondern Debug das doch einfach mal.
Haltepunkt reinsetzen, und im lokalfenster gucken, obs tut was es soll.
Zum Relationen-Problem: ja, da hatte ich ja richtig geahnt, dass du nicht nur Parent-werte anzeigen und filtern willst, sondern Parent-Parent-Werte. Das geht klassisch dann nur noch, indem man zusätzliche DataExpression-Spalten einbastelt - findich auch nicht schön.
Aber ich guckma, ob man per Formatting-Event gefakte ungebundene Spalten - nee, filtern kannste damit auch nicht. Filtern kann man numal nur, was inne DataTable auch da ist.
Tja. -
ErfinderDesRades schrieb:
Sieht mir sehr falsch aus. Aber ich sag nicht vor, sondern Debug das doch einfach mal.
Haltepunkt reinsetzen, und im lokalfenster gucken, obs tut was es soll.
Jetz is mir auch klar, warum der keinen Fehler gezeigt hat. Die ComboBoxen liegen auf dem EditDialog und der wird nicht
mit ControlStyling geöffnet.
Geht nun, der richtige Code an der Stelle ist
und ich musste dein BindingSourceX noch anpassen (außerdem hab ich die ControlStyling.vb in deine Helpers geschoben)
Zeile 4 beinhaltet nun das ControlStyling, auch für die DetailDialoge
VB.NET-Quellcode
- Private Function EditItem(Of T As {Form, New})(bs As BindingSource, item As Object) As DialogResult
- Dim tb = DirectCast(item, DataRowView).Row.Table
- Using frm = New T
- ControlStyling.StyleControls(frm)
- tb.DataSet.Register(frm, False)
- Dim allCtls = New GetChilds(Of Control)(Function(ctl) ctl.Controls).AllAsList(frm)
- Dim bindFlags As BindingFlags = BindingFlags.Instance Or BindingFlags.Public _
- Or BindingFlags.NonPublic Or BindingFlags.GetField
- For Each ctl In allCtls.Where(Function(c) TypeOf c Is ContainerControl AndAlso TypeOf c Is Form OrElse TypeOf c Is UserControl)
- For Each fld In ctl.GetType.GetFields(bindFlags).Where(Function(f) f.FieldType = GetType(BindingSource))
- Dim bs2 = DirectCast(fld.GetValue(ctl), BindingSource)
- If bs2 Is Nothing Then Continue For
- If tb Is bs2.DataTable Then
- bs2.DataSource = item
- EditItem = frm.ShowDialog()
- If EditItem = Windows.Forms.DialogResult.OK Then
- bs2.EndEdit()
- bs.ResetCurrentItem() 'den von der anneren BS geänderten Datensatz neu einlesen.
- Else
- bs.CancelEdit()
- End If
- Exit Function
- End If
- Next
- Next
- Throw New Exception("es konnte keine geeignete BindingSource gefunden werden.".And2(
- "\nHinweis:",
- "\nDie Extension-Method '<BindingSource>.", (New StackTrace).GetFrame(1).GetMethod.Name, "()' funktioniert nur, wenn zuvor",
- "\n<", tb.DataSet.GetType.Name, ">.Register(<", GetType(T).Name, ">)",
- "\naufgerufen wurde."))
- End Using
- End Function
ErfinderDesRades schrieb:
Zum Relationen-Problem: ja, da hatte ich ja richtig geahnt, dass du nicht nur Parent-werte anzeigen und filtern willst, sondern Parent-Parent-Werte. Das geht klassisch dann nur noch, indem man zusätzliche DataExpression-Spalten einbastelt - findich auch nicht schön.
Aber ich guckma, ob man per Formatting-Event gefakte ungebundene Spalten - nee, filtern kannste damit auch nicht. Filtern kann man numal nur, was inne DataTable auch da ist.
Tja.
JO, genau so hab' ich mir das schon gedacht. Ich hab mir jetzt geholfen, indem ich überall wo's geht den Wert speichere, den ich auch zum späteren Aufruf wieder brauche. Funzt auch - bezieht sich allerdings nicht immer auf den PK.
Das hier bekomm ich im Übrigen nicht in die Helpers geschoben, weil der Dts dann nicht mehr erkennt. Und mitImports Logistik_Tool.dtsLogistik
brauch ich da nicht anfangen weil mein Projekt zwar mit den Helpers verlinkt ist (über Verweise) aber umgekehrt nicht. Welche Weg muss ich gehen um das Dts dort
bekannt zu machen?
"Na, wie ist das Wetter bei dir?"
"Caps Lock."
"Hä?"
"Shift ohne Ende!" -
Es muss nicht alles in meine Helpers.
Da gehören eiglich nur Sachen rein, die auch in anderen Solutions nützlich sein können.
Also das ControlStyling eher nicht.
In meine (grossen) Helpers hab ich ein ControlStyling drin, was nur als Kopiervorlage dient.
Wenn ich dann in einem Projekt mit ControlStyling arbeiten will, kopiere ich das da hinein, und passe die Kopie an die Erfordernisse des Projekts an.
Weil eiglich jede Solution braucht im Main-Projekt das ControlStyling bischen anders.
Auch ShowDataDialog hat keine wirklich projektübergreifende Gültigkeit - ist ja nicht gesagt, dass du nu für immer beim Schliessen eines DataDialogs auch gleich das Dataset speichern willst (obwohl - könnte man sich drauf einigen).
Und das mit EditItem würde ich jetzt nochmal anders machen - dass man da wirklich ein Dialog-Objekt übergeben muss - nicht nur einen Dialog-TypParameter.
Dann kann man das ControlStyling beim Aufrufer im Projekt lassen.
Aber das sind eher kleinliche Architektur-Fragen - um die kannste dich kümmern, musste aber jetzt noch nicht.
Das wird erst interessant, wenn du auf deine Helpers tatsächlich aus mehreren Solutions verweist.
Dazu müssten sie auch im Dateisystem mindestens eine Ebene höher liegen - richtige Helpers können nicht in irgendeinem Solution-Ordner liegen, sondern müssen ausserhalb.
-
ErfinderDesRades schrieb:
Es muss nicht alles in meine Helpers.
Da gehören eiglich nur Sachen rein, die auch in anderen Solutions nützlich sein können.
Also das ControlStyling eher nicht.
In meine (grossen) Helpers hab ich ein ControlStyling drin, was nur als Kopiervorlage dient.
Wenn ich dann in einem Projekt mit ControlStyling arbeiten will, kopiere ich das da hinein, und passe die Kopie an die Erfordernisse des Projekts an.
Weil eiglich jede Solution braucht im Main-Projekt das ControlStyling bischen anders.
Auch ShowDataDialog hat keine wirklich projektübergreifende Gültigkeit - ist ja nicht gesagt, dass du nu für immer beim Schliessen eines DataDialogs auch gleich das Dataset speichern willst (obwohl - könnte man sich drauf einigen).
Ok, dann änder' ich das wieder ab - macht Sinn.
Hab' noch einen spezialgelagerten Sonderfall:
Aus Form Übersicht (bsUrlaub -> DGV mit Daten aus Tabelle wird angezeigt) rufe ich über bs.EditNew(...) den DetailDialog auf. (bsUrlaubsplan_Detail)
beide BS beziehen sich auf die selbe Tabelle.
Dort habe ich testweise einen Datumsbereich eingebaut. Wie schaffe ich es nun, dass er mir für jedes Datum im Bereich einen neuen Datensatz anlegt?
So geht das leider nicht:
VB.NET-Quellcode
- Private Sub dlgUrlaubDetail_FormClosing(sender As Object, e As FormClosingEventArgs) Handles Me.FormClosing
- If ArtTextBox.Text <> "" Then
- If cbBereich.Checked = True Then
- Dim startDate As Date = dtpVon.Value
- Dim endDate As Date = dtpBis.Value
- Dim i As Date = startDate
- Do While i < endDate
- bsUrlaubsplan_Detail.AllowNew = True
- bsUrlaubsplan_Detail.AddNew()
- i = i.AddDays(1)
- Loop
- End If
- Dts.SaveDts(Me)
- Else
- msgInformation("Das Feld Art muss ausgefüllt sein!")
- e.Cancel = True
- End If
- End Sub
Bzw. die beiden Felder (dtpVon und dtpBis) sind ja garnicht an die BS gebunden - also andere Frage: gibt's eine Variante,
das Feld "Datum" in der Detailansicht auf 2 Felder zu erweitern und somit mehrere Datensätze gleichzeitig zu erzeugen?
"Na, wie ist das Wetter bei dir?"
"Caps Lock."
"Hä?"
"Shift ohne Ende!"Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „tragl“ ()
-
Wenn du typisierte Datensätze einer typisierten Tabelle zufügen willst, dann füge typisierte der typisierten Tabelle zu.
Nicht einer BindingSource, und nicht einem Datagridview (falls du auf diese Idee kommen solltest).
Die typisierte Tabelle hat eine typisierte Methode zum Zufügen typisierter Datensätze.
Schau dazu unbedingt die Tuts durch, sonst machst du es falsch.
Es gibt immer 2 typisierte Add-Methoden, und die mit den vielen Parametern ist vorzuziehen.
Ich weiss nicht, in welchen Tuts das überall vorkommt, aber im englischen, Teil 3 gehe ich glaub ganz speziell darauf ein, dass man das typisierte Dataset auch typisiert benutzt.
tragl schrieb:
Bzw. die beiden Felder (dtpVon und dtpBis) sind ja garnicht an die BS gebunden - also andere Frage: gibt's eine Variante,
das Feld "Datum" in der Detailansicht auf 2 Felder zu erweitern und somit mehrere Datensätze gleichzeitig zu erzeugen?
Also dein Code soweit richtig, zur Zeilen #8,9 wären durch einenDts.UrlaubsDetail.AddUrlaubsDetailRow()
- Aufruf zu ersetzen.
Zu überlegen auch, ob das Detailform das selbst macht, oder ob das der Aufrufer machen soll.
Weil im Aufrufer wird ja das DialogResult abgeprüft, und wenn das nicht Ok ist, darf ja nix passieren.
Früher dachte ich immer, architektonisch sauber wäre, wenn unbedingt der Aufrufer das macht, aber letztendlich bin ich nicht mehr sicher, obs so nicht ebensogut ist:
Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „ErfinderDesRades“ ()
-
ErfinderDesRades schrieb:
Also dein Code soweit richtig, zur Zeilen #8,9 wären durch einen Dts.UrlaubsDetail.AddUrlaubsDetailRow() - Aufruf zu ersetzen.
Edit: OK, ich hab's bis auf ein Problem:
Wenn beide Datumsfelder gleich sind dann wird kein Eintrag erstellt. Ich nehme an, Zeile 15 muss dazu angepasst werden? Aber wie? Oder noch eine If-Klausel verbasteln?
Das "For Each" (Zeile 26+28) gefällt mir noch nicht - eigentlich sinnlos, da es den Mitarbeiter anhand der ID ja nur einmal gibt aber ich weiß keinen anderen weg
um an "rw" zu kommen.
Ansonsten wird eine Length von "1" für die Textbox vorgegeben. Geprüft wird:
- Ob Textbox "Art" ausgefüllt ist
- Ob von-Datum kleiner Bis-Datum ist
- Eingaben in die Textbox "Art" (ob die richtigen Chars eingetragen wurden)
- Ob es schon einen Eintrag für den Mitarbeiter an dem Datum gibt
- Ob der Datumsbereich > 14 Tage ist
Hat man vor dem Aufruf des Dialogs Zeilen gelöscht und das wurde nicht im DTS gespeichert, kam es zu einem Fehler nach Schließen des Dialogs,
er könne die gelöschten Zeilen nicht erkennen (trat bei DTS.Save auf). Außerdem muss ich nach Beenden des Dialogs das DTS reloaden, da sonst der "Standardeintrag(mit den Standardwerten
der Tables) noch drin steht. Hab das aber lösen können -
Vielleicht alles nicht die schönste Art - aber es klappt!
VB.NET-Quellcode
- Private Sub ts_Click(sender As Object, e As EventArgs) Handles tsBearbeiten.Click, tsNeu.Click
- Select Case True
- Case sender Is tsBearbeiten : bsUrlaub.EditCurrent(Of dlgUrlaubDetail)
- Case sender Is tsNeu
- If Dts.HasChanges Then
- If msgQuestionInfo("Soll der Löschvorgang gespeichert werden?") = DialogResult.Yes Then
- Dts.SaveDts(Me)
- Else
- Dts.ReloadDts()
- End If
- End If
- bsUrlaub.EditNew(Of dlgUrlaubDetail)
- Dts.ReloadDts()
- End Select
- End Sub
VB.NET-Quellcode
- Private Sub dlgUrlaubDetail_FormClosing(sender As Object, e As FormClosingEventArgs) Handles Me.FormClosing
- If Me.DialogResult <> DialogResult.OK Then Return
- If ArtTextBox.Text <> "" Then
- If Not dtpVon.Value > dtpBis.Value Then
- If ArtTextBox.Text = "U" Or ArtTextBox.Text = "u" Or ArtTextBox.Text = "K" Or ArtTextBox.Text = "k" Then
- Dim selectedMitarbeiterID = cbMitarbeiter.SelectedValue.ToString
- Dim startDate As Date = Date.Parse(dtpVon.Value.ToShortDateString)
- Dim endDate As Date = Date.Parse(dtpBis.Value.ToShortDateString)
- Dim differenz = endDate.Subtract(startDate).TotalDays
- If differenz > 14 Then
- If msgQuestionWarning($"Der Datumsbereich beträgt {differenz.ToString} Tage, wirklich weitermachen?") = DialogResult.No Then
- e.Cancel = True
- Else
- Dim i As Date = startDate
- Do While i < endDate.AddDays(1)
- Dim urlaubTabelle = Dts.Urlaubsplan.Cast(Of UrlaubsplanRow)
- For Each rw2 In urlaubTabelle
- If rw2.Datum = i Then
- If rw2.MitarbeiterID = CType(selectedMitarbeiterID, Double) Then
- msgInformation($"Es existiert schon ein Eintrag für den {i.ToShortDateString}")
- Return
- End If
- End If
- Next
- Dim maParent = Dts.Mitarbeiter.Select($"ID = {selectedMitarbeiterID}").Cast(Of MitarbeiterRow)
- For Each rw In maParent
- Dts.Urlaubsplan.AddUrlaubsplanRow(i, rw, CType(ArtTextBox.Text, Char), BemerkungTextBox.Text)
- Next
- i = i.AddDays(1)
- Loop
- Dts.SaveDts(Me)
- End If
- End If
- Else
- msgExclamation("Es dürfen nur die Buchstaben U,u,K,k verwendet werden!")
- ArtTextBox.Select()
- e.Cancel = True
- End If
- Else
- msgInformation("Datum VON muss kleiner BIS sein!")
- dtpVon.Select()
- e.Cancel = True
- End If
- Else
- msgInformation("Das Feld Art muss ausgefüllt sein!")
- ArtTextBox.Select()
- e.Cancel = True
- End If
- End Sub
"Na, wie ist das Wetter bei dir?"
"Caps Lock."
"Hä?"
"Shift ohne Ende!"Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „tragl“ ()
-
Du arbeitest noch nicht wirklich mit dem typisierten Dataset. ZB wann immer du eine ID benötigst, ist wahrscheinlich was falsch.
Weil im typDataset sind alle datensätze direkt verknüpft - iwas über eine ID zu suchen braucht man nicht.
zB zeile#6
Da holst du dir die mitarbeiter Row lieber gleich:
Dann kannste dir weiter unten diese Gräuseligkeit glaub sparen
Hier setzt sich das Unglück dann fort:Hättest du dir oben gleich die ganze MitarbeiterRow geholt, hiesse dasAber dassis höchstwahrscheinlich auch Quark, weil es im typDataset kann man ja alle ChildRows direkt abrufen:Damit kommste vermutlich viel direkter zum Ziel (was immer das auch ist).
Guck dir das typDataset im Objectbrowser an! Alle typisierten Properties und Methoden aller Tabellen, und aller typisierten Rows. (naja, nach jeweils zwei oder 3 typisierten Tabellen/Rows wirste das System schnackeln).
Ist kein Zufall, dassich zu ObjectBrowser und typDataset-Gucken im englischen Tut-3 einen sehr ausführlichen Exkurs verzapft hab.
rw2
ist auch ein schlechter Name für eine typisierte Row - insbesondere wenn verschiedene typisierte Typen miteinander in Beziehung treten. Man weiss bei rw2 nicht: ists ein Mitarbeiter, ein UrlaubsPlan, oder gar eine untypisierte Abscheulichkeit?
Und guck dir im ObjectBrowser auch primitive Datentypen an - insbesondere Date, Timespan, String. Die haben sehr viele Möglichkeiten.
Vor allem wenn was scheinbar häufig benötigtes umständlich zu sein scheint:
DataTable.Select(String)
ist untypisiert, also böse. Wenn du meinst, sowas zu brauchen, guck das typisierte Dataset im ObjectBrowser an, oder frag im Forum.
(Das habich nur einmal beim Treeview-Bauen verwendet (von dir übernommen), weil man damit dynamisch verschiedene Spalten abfragen kann)
noch ein:
Bitte benenne einDate
nichti
.
Jo, warums bei beide DatumsFelder gleich keine Treffer gibt, weiss ich auch nicht - also ich seh da grad nix.
Eine ganz allgemeine Regel: Jede erzwungene Typumwandlung ist böse, oder zumindest verdächtig.
Das Typsystem der Sprache ist dazu da, die Programmierung in sinnvolle Bahnen zu lenken.
DirectCast, TryCast, CType, CInt, .Cast(Of ), .ToString
sind Krücken, die man verwendet, wenn Dinge nicht zusammenpassen.
Dann muss man fragen: Ist das wirklich unvermeidlich, dass diese Dinge nicht zusammenpassen? Oder bin ich auffm falschen Dampfer, dass ich da mit Gewalt versuche, was eiglich nicht vorgesehen ist? Hat das einen Grund, dasses nicht vorgesehen ist?
DirectCast, TryCast, CType, CInt, .Cast(Of )
Sie sind auch direkt gefährlich: kannste auf jedes Objekt anwenden - Der Compiler kann nicht überprüfen, ob die Umwandlung funktionieren wird.
Keine Ahnung - vermutlich an 50 - 80% aller Laufzeitfehler sind nicht-funktionierende Typumwandlungen zumindest beteiligt.
Dieser Beitrag wurde bereits 8 mal editiert, zuletzt von „ErfinderDesRades“ ()
-
ErfinderDesRades schrieb:
DataTable.Select(String) ist untypisiert, also böse. Wenn du meinst, sowas zu brauchen, guck das typisierte Dataset im ObjectBrowser an, oder frag im Forum.
(Das habich nur einmal beim Treeview-Bauen verwendet (von dir übernommen), weil man damit dynamisch verschiedene Spalten abfragen kann)
Moin. Ich hatte ja gesagt, dass der Code alles Andere als optimal ist - du hast nun wesentlich mehr Erfahrung
Aber gut, ich will ja lernen - also umgebaut sieht das wie folgt aus:
VB.NET-Quellcode
- Private Sub dlgUrlaubDetail_FormClosing(sender As Object, e As FormClosingEventArgs) Handles Me.FormClosing
- If Me.DialogResult <> DialogResult.OK Then Return
- If ArtTextBox.Text <> "" Then
- If Not dtpVon.Value > dtpBis.Value Then
- If ArtTextBox.Text = "U" Or ArtTextBox.Text = "u" Or ArtTextBox.Text = "K" Or ArtTextBox.Text = "k" Then
- Dim startDatum = Date.Parse(dtpVon.Value.ToShortDateString)
- Dim endDatum = Date.Parse(dtpBis.Value.ToShortDateString)
- Dim datumDifferenz = endDatum.Subtract(startDatum).TotalDays
- Dim rwMitarbeiter = bsCbcMitarbeiter_Detail.At(Of MitarbeiterRow)
- If datumDifferenz > 14 Then
- If msgQuestionWarning($"Der Datumsbereich beträgt {datumDifferenz.ToString} Tage, wirklich weitermachen?") = DialogResult.No Then Return
- End If
- Dim loopDatum = startDatum
- Do While loopDatum < endDatum.AddDays(1)
- For Each rwUrlaub In Dts.UrlaubKrank
- If rwUrlaub.Datum = loopDatum Then
- If rwUrlaub.MitarbeiterID = rwMitarbeiter.ID Then
- msgInformation($"Es existiert schon ein Eintrag für den {loopDatum.ToShortDateString}")
- Return
- End If
- End If
- Next
- Dts.UrlaubKrank.AddUrlaubKrankRow(loopDatum, rwMitarbeiter, CType(ArtTextBox.Text, Char), BemerkungTextBox.Text)
- loopDatum = loopDatum.AddDays(1)
- Loop
- Dts.SaveDts(Me)
- Else
- msgExclamation("Es dürfen nur die Buchstaben U,u,K,k verwendet werden!")
- ArtTextBox.Select()
- e.Cancel = True
- End If
- Else
- msgInformation("Datum VON muss kleiner BIS sein!")
- dtpVon.Select()
- e.Cancel = True
- End If
- Else
- msgInformation("Das Feld Art muss ausgefüllt sein!")
- ArtTextBox.Select()
- e.Cancel = True
- End If
- End Sub
ErfinderDesRades schrieb:
Wobei ich mit dem Tabellen Namen nicht sehr glücklich bin: Es sind keine UrlaubsPläne darin.
Ja, sowas passiert auf die Schnelle ohne groß nachzudenken. Ich hab die Table nun inUrlaubKrank
umbenannt.
ErfinderDesRades schrieb:
'Statt
Dim startDate As Date = Date.Parse(dtpVon.Value.ToShortDateString)
'heisstes
Dim startDate = dtpVon.Value.Date
Dim endDate = dtpBis.Value.Date.AddDays(1)
Jain. Mir ist es wichtig, dass von Anfang an mit ShortDate gearbeitet wird, deshalb hab ich das da auch so angegeben. Ich kann mit DatumUhrzeit nix anfangen und das auch net gebrauchen.
ErfinderDesRades schrieb:
Bitte benenne ein Date nicht i.
ist nun auch geändert - hatte ich aus einem Beispiel im Forum erstmal so übernommen.
So klappt das nun und ich hab' wieder was gelernt. Mit dem OB muss ich mich noch auseinandersetzen - den hab ich bei VBA auch nie wirklich genutzt (ist aber sinnvoll)
Auch 2 gleiche Datum's klappt jetzt (warum auch immer)
Was ich noch nicht ganz verstehe:
Setze ich in Zeile 11+19 stattReturn
e.Cancel = True
dann geht er zwar zurück zur Eingabe aber erstellt trotzdem die ganzen Einträge
Schöner wär's hier wenn er die Form nicht schließen würde (Return), sondern würde zurück zur Eingabemaske gehen sodass der User das korrigieren kann."Na, wie ist das Wetter bei dir?"
"Caps Lock."
"Hä?"
"Shift ohne Ende!" -
tragl schrieb:
Mir ist es wichtig, dass von Anfang an mit ShortDate gearbeitet wird
Schau mein Code genau - der greift nur das Datum ab.
Und schau dir wie gesagt dieDateTime
-Struktur im ObjectBrowser an (UndTimeSpan, String, List(Of T), Array
ebenfalls)
ZB diese Möglichkeit findet sich da auch:
tragl schrieb:
Setze ich in Zeile 11+19 statt Return e.Cancel = True dann geht er zwar zurück zur Eingabe aber erstellt trotzdem die ganzen Einträge
-
ErfinderDesRades schrieb:
Schau mein Code genau - der greift nur das Datum ab.
Sorry, da hab' ich mal wieder nicht genau gelesen..Date
hatte ich übersehen. Hab's geändert
Hast du noch einen Tipp für mich, wie ich eine Bindingsource nach Übergeordneten Elementen Filtere?
Hier will ich die Urlaub der Mitarbeiter anzeigen lassen, die dem Ausgewählten Standort aus der ComboBox entsprechen.
Mache ich hierbsUrlaub.Filter = $"Standort = '{CboxStandort.Text}'"
findet er logischerweise
die Standort-Spalte in Urlaub nicht, weil die ist ja nur in Mitarbeiter vorhanden. Ich müsste also über die MitarbeiterID gehen, nur wie?
Geht vermutlich wieder ganz einfach über typDs aber ich steh' grad aufm Schlauch"Na, wie ist das Wetter bei dir?"
"Caps Lock."
"Hä?"
"Shift ohne Ende!" -
ich sags nochma (oder habichdas noch nie?): Nimm zur Datenverarbeitung die BindingSource - nicht iwelche Controls.
Probierma:bsUrlaub.Filter = $"StandortID = '{bsStandort.At(Of StandortRow).ID}'"
Also genau genommen heisst die Regel: immer möglichst nah anne Daten verarbeiten, und möglichst weit weg vonne Controls.
Also eine Art Datenverarbeitungs-Ranking- Verwende vorzugsweise die typisierten Tabellen.
- Wenn das nicht geht, greife in die BindingSource (Etwa, wenn eine Konkrete Auswahl getroffen ist - ist die ja aus der typTable nicht zu ersehen).
- Wenn das nicht geht, musste wohl ins Control grabschen (dafür hatten wir bisher noch kein Beispiel - denkbar wäre etwa die Mehrfach-Selection im DGV verarbeiten zu wollen - das übermittelt eine BS ja nicht.)
Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „ErfinderDesRades“ ()
- Verwende vorzugsweise die typisierten Tabellen.
-
ErfinderDesRades schrieb:
ich sags nochma (oder habichdas noch nie?): Nimm zur Datenverarbeitung die BindingSource - nicht iwelche Controls.
Probierma: <code class="inlineCode">bsUrlaub.Filter = $"StandortID = '{bsStandort.At(Of StandortRow).ID}'"</code>
Also genau genommen heisst die Regel: immer möglichst…
Geht leider so nicht, ich glaub auch das war falsch rüber gekommen.
wie hier im DataSet zu sehen, gibt's bei UrlaubKrank den Standort garnicht.
Der kommt im DGV über die MitarbeiterID mit (ich hab mal kläglich versucht das aufzumalen )
Also müsste das was sein wie
bsFilter = zeige mir die Mitarbeiter, deren Standort ich aus der ComboBox "Standort" ausgewählt hab
ICh studier' aber grad deine Videos - vermutlich (hoffentlich) werd ich da einen Anhaltspunkt finden
"Na, wie ist das Wetter bei dir?"
"Caps Lock."
"Hä?"
"Shift ohne Ende!" -
tragl schrieb:
Also müsste das was sein wie
bsFilter = zeige mir die Mitarbeiter, deren Standort ich aus der ComboBox "Standort" ausgewählt hab
ICh studier' aber grad deine Videos - vermutlich (hoffentlich) werd ich da einen Anhaltspunkt finden
Also wenn du wirklich das meinst, was du sagst: "zeige mir die Mitarbeiter, deren Standort ich aus der ComboBox "Standort" ausgewählt hab".
Dazu muss bsStandort als DataSource von bsMitarbeiter gesetzt sein.
Wenn cmbStandort dann bsStandort als DataSoruce hat, dann zeigt bsMitarbeiter die Mitarbeiter des in der Combo gewählten Standorts an.
(Da weiss ich dann aber nun wieder nicht, was das mit UrlaubKrank zu tun hat.)
Wie dem auch sei - am oben ausgeführten Grundprinzip: "prefer Dataset-Access over BindingSource-Access, over Control-Access" ändert das nix.
-
Ähnliche Themen
-
menorca - - Sonstige Problemstellungen
-
5 Benutzer haben hier geschrieben
- tragl (179)
- ErfinderDesRades (146)
- VaporiZed (20)
- petaod (4)
- Kasi (3)