Daten Filtern und Drucken

  • VB.NET

Es gibt 16 Antworten in diesem Thema. Der letzte Beitrag () ist von ErfinderDesRades.

    Daten Filtern und Drucken

    Hallo zusammen,
    ich habe folgendes DataSet.



    Und dazu folgende Form.



    Nun möchte ich bestimmte Werte aus den Tabellen Filtern und Drucken.

    Mit folgendem Code z.b. Drucke ich alle VertriebMitarbeiter und wann deren Pläne bearbeitet wurden (EinstellDatum und UploadDatum)

    VB.NET-Quellcode

    1. With e.Graphics
    2. .DrawString("Mitarbeiter", _font, _brush, x, y)
    3. .DrawString("Einstelldatum", _font, _brush, x + 200, y)
    4. .DrawString("Upoaddatum", _font, _brush, x + 400, y)
    5. For i = 0 To bsPlan.Count - 1
    6. Dim rwPlan = bsPlan.At(Of PlanRow)(i)
    7. .DrawString(rwPlan.VertriebMitarbeiterRow.Name, _font, _brush, x, y + LineHeight)
    8. .DrawString(rwPlan.EinstellDatum.ToShortDateString, _font, _brush, x + 250, y + LineHeight)
    9. .DrawString(rwPlan.Uploaddatum.ToShortDateString, _font, _brush, x + 450, y + LineHeight)
    10. y += LineHeight
    11. Next
    12. End With


    Wie aber kann ich die Pläne nach Datum filtern und mir dann dazu den VertriebMitarbeiter und die Anzahl seiner Pläne Drucken?
    Ich möchte also wissen welcher Mitarbeiter hat wie viele Pläne vom 01.06.2017 bis 30.06.2017 bearbeitet.
    Ich bekomme den Filter nicht hin das ich es auch zum drucken verwenden kann.

    Hat da jemand einen Denkanstoss für mich?
    Kann / sollte man das mit Linq machen oder brauch man das überhaupt nicht?
    Rechtschreibfehler betonen den künstlerischen Charakter des Autors.
    @Akanel
    Setz' doch Deine filter auf die Filter-Property der Bindingsource bsPlan:

    VB.NET-Quellcode

    1. bsPlan.Filter = "Einstelldatum = >=#2017/06/01# AND UploadDatum = <=#2017/06/31#"
    . Dann hast Du zumindes schon einmal den Zeitraum eingegrenzt.
    Ist es aber nicht so, das immer nur EIN Mitarbeiter einen Kunden bearbeitet? Dann kannstDu Deine Relationen anders setzen:
    KUNDE ==> VERTRIEBMITARBEITER = > PLAN
    Im typisierten Dataset findest Du dann in der VertriebMitarbeiterRow eine Property GetPlanRows, die eine Enumeration(Of PlanRow) zurückgibt. Und die wiederum hat die Property COUNT.

    Du Kannst dann auch eine weitere Relation setzen:
    KUNDE ==> PLAN
    Damit ist dann einfach zu sehen, weleche Pläne zu einem Kunden gehören, den es gibt in der KundenRow dann ebenfalls die Property GetPlanRows. Und umgekehrt kannst Du von einer PlanRow den Kunden erkennen.

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

    Hallo @us4711

    Also das Filtern habe ich mit Hilfe von @ErfinderDesRades seiner Extension gemacht. Der Filter war ja auch schon in der Form eingebaut.
    Somit ist schon ein Teil, den ich ausdrucken möchte, gefiltert. Ich hatte das nur nicht gerafft und auf Krampf versucht eine Lösung zu finden, dabei war sie schon längst da. :/

    Hier erstmal der komplette Code den ich bisher habe. Das DataSet ist noch so wie oben auf dem Bild zu sehen.
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Imports System.Drawing.Printing
    2. Imports System.IO
    3. Imports Hartmann.Dts
    4. Public Class Form1
    5. Private _dataPath As String = Path.GetFullPath("Plaene.xml")
    6. Private Sub DatenSpeichern()
    7. Me.Validate()
    8. Dts1.WriteXml(_dataPath)
    9. End Sub
    10. Private Sub DatenLaden()
    11. Dts1.Clear()
    12. For Each tb As DataTable In Dts1.Tables
    13. tb.BeginLoadData()
    14. Next
    15. If File.Exists(_dataPath) Then Dts1.ReadXml(_dataPath)
    16. For Each tb As DataTable In Dts1.Tables
    17. tb.EndLoadData()
    18. Next
    19. Dts1.EnforceConstraints = True
    20. End Sub
    21. Private Sub Form1_FormClosed(sender As Object, e As FormClosedEventArgs) Handles Me.FormClosed
    22. With Me
    23. If .DialogResult <> DialogResult.None Then Return
    24. .Validate()
    25. .SuspendLayout()
    26. With .Controls
    27. While .Count > 0 : .Item(.Count - 1).Dispose() : End While
    28. End With
    29. End With
    30. End Sub
    31. Private Sub Form1_FormClosing(sender As Object, e As FormClosingEventArgs) Handles Me.FormClosing
    32. If Not Dts1.HasChanges Then Return
    33. DatenSpeichern()
    34. End Sub
    35. Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Shown
    36. DatenLaden()
    37. End Sub
    38. Private Sub MenuStrip1_Click(sender As Object, e As EventArgs) Handles btnLaden.Click, btnSpeichern.Click, btnTest.Click
    39. Select Case True
    40. Case sender Is btnLaden : DatenLaden()
    41. Case sender Is btnSpeichern : DatenSpeichern()
    42. Case sender Is btnTest : Test()
    43. End Select
    44. End Sub
    45. Private Sub btnFiltern_Click(sender As Object, e As EventArgs) Handles btnFiltern.Click
    46. bsPlan.FilterX("UploadDatum >= ? AND UploadDatum <= ? ", dtpVon.Value, dtpBis.Value)
    47. End Sub
    48. Private Sub btnResetFilter_Click(sender As Object, e As EventArgs) Handles btnResetFilter.Click
    49. bsPlan.FilterX("")
    50. End Sub
    51. Private Sub btnDrucken_Click(sender As Object, e As EventArgs) Handles btnDrucken.Click
    52. PrintPreviewDialog1.Document = PrintDocument1
    53. PrintPreviewDialog1.WindowState = FormWindowState.Maximized
    54. PrintPreviewDialog1.PrintPreviewControl.Zoom = 1
    55. PrintPreviewDialog1.ShowDialog(Me)
    56. End Sub
    57. Private Sub Test()
    58. bsPlan.FilterX("UploadDatum >= ? AND UploadDatum <= ? ", dtpVon.Value, dtpBis.Value)
    59. End Sub
    60. Private Sub PrintDocument1_PrintPage(sender As Object, e As PrintPageEventArgs) Handles PrintDocument1.PrintPage
    61. Dim _font As New Font("Segoe UI", 11.0!)
    62. Dim _brush As Brush = Brushes.Black
    63. Dim LineHeight As Single = _font.GetHeight(e.Graphics) + 5
    64. Dim x As Single = e.MarginBounds.Left
    65. Dim y As Single = e.MarginBounds.Top
    66. With e.Graphics
    67. '###### Mitarbeiter mit zugehörigem Plan ######
    68. .DrawString("Mitarbeiter", _font, _brush, x, y)
    69. .DrawString("Einstelldatum", _font, _brush, x + 200, y)
    70. .DrawString("Upoaddatum", _font, _brush, x + 400, y)
    71. For i = 0 To bsPlan.Count - 1
    72. Dim rwPlan = bsPlan.At(Of PlanRow)(i)
    73. .DrawString(rwPlan.VertriebMitarbeiterRow.Name, _font, _brush, x, y + LineHeight)
    74. .DrawString(rwPlan.EinstellDatum.ToShortDateString, _font, _brush, x + 250, y + LineHeight)
    75. .DrawString(rwPlan.Uploaddatum.ToShortDateString, _font, _brush, x + 450, y + LineHeight)
    76. y += LineHeight
    77. Next
    78. '###### Mitarbeiter mit Anzahl der zugehörigen Pläne ######
    79. .DrawString("Vertriebmitarbeiter", _font, _brush, x, y + 200)
    80. .DrawString("Anzahl Pläne", _font, _brush, x + 200, y + 200)
    81. For i = 0 To bsVertriebMitarbeiter.Count - 1
    82. Dim rwVMA = bsVertriebMitarbeiter.At(Of VertriebMitarbeiterRow)(i)
    83. Dim rwPlan = rwVMA.GetPlanRows.Length
    84. .DrawString(rwVMA.Name, _font, _brush, x, y + 200 + LineHeight)
    85. .DrawString(rwPlan.ToString, _font, _brush, x + 200, y + 200 + LineHeight)
    86. y += LineHeight
    87. Next
    88. End With
    89. End Sub
    90. End Class


    Wie Du siehst nutze ich GetPlanRows() bereits, um mir die Anzahl der Pläne zu jedem VertriebMitarbeiter anzeigen zu lassen.

    Was mir jetzt noch fehlt ist , das diese auch nach dem Datum gefiltert werden. Und da stehe ich auf dem Schlauch.


    An das Umsetzen der Relationen hatte ich auch schon gedacht, allerdings ist es in der Tat so das Pro Kunde mehrere VertriebMitarbeiter vorkommen können. Macht eigentlich keinen Sinn, ist aber leider so.
    Rechtschreibfehler betonen den künstlerischen Charakter des Autors.
    Ja das ist die bsPlan. Aber da bekomme ich es nicht hin das mir in dem gefilterten Zeitraum die Mitarbeiter, mit der Anzahl an Plänen die sie in dem Zeitraum erstellt haben, angezeigt wird.
    Ich habe die bsPlan ja schon gefiltert nach dem Datum (1. Block in der Printroutine). Aber dort wird jeder Plan pro Mitarbeiter einzeln aufgeführt, nicht zusammengefasst.

    Ich hänge mal einen Screenshot an wie derzeit die Ausgabe ist.
    Ich hätte gerne das UNTERE nach Datum gefiltert.

    Wie Du siehst sind oben 8 Datensätze an Plänen, unten hingegen sind es neun Pläne (zusammengezählt). Das liegt daran das der filter einen Plan ausschließt, aber leider nur oben.

    Funktioniert das hier nur mit LINQ?

    Rechtschreibfehler betonen den künstlerischen Charakter des Autors.
    Dann habe ich ja die Anzahl der Pläne von jedem Mitarbeiter. Aber diese sind ja immer gesamt gezählt. Wenn ich jetzt wissen möchte wieviele das z.b. nur im August sind funktioniert das ja auch nicht.

    Ich habe das Gefühl ich habe mein Problem nicht richtig beschrieben.

    Ich hänge als beispiel mal meine Solution an. Es geht mir dabei um die Auswertung die beim Drucken rauskommt.
    Klick in der Solution mal "Filter" und dann "Drucken".
    Oben werden alle Mitarbeiter mit Daten zum Plan ausgegeben.
    Im unteren Teil soll jeder Mitarbeiter mit Anzahl der Pläne in diesem Zeitraum aufgelistet werden. Und hier ist das Problem mit dem Filtern des Zeitraumes.
    Dateien
    • Hartmann.rar

      (273,14 kB, 79 mal heruntergeladen, zuletzt: )
    Rechtschreibfehler betonen den künstlerischen Charakter des Autors.
    OK.
    Tausch' mal Zeile 100 aus:

    VB.NET-Quellcode

    1. Dim rwPlan = rwVMA.GetPlanRows.Where(Function(f) f.Uploaddatum >= dtpVon.Value AndAlso f.Uploaddatum <= dtpBis.Value).Count

    Der auf die Bindingsource gesetzte Filter wirkt sich NICHT auf die ChildTable der Mitarbeiter aus, da die Relation ja nicht auf die Relation Mitarbeiter=>Pläne wirkt, sondern direkt auf die Tabelle Pläne.
    Kann daher nicht funktionieren, da es eine andere Sicht auf die Daten ist, ebne auf ALLE Pläne, und nicht nur auf die Pläne des Mitarbeiters.

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

    Ganz ehrlich. Ich habe im OB geschaut was ich machen kann, aber meine Kenntnis reicht scheinbar noch nicht soweit das richtige zu erkennen.
    Selbst jetzt wo du mich mit der Nase drauf drückst, finde ich es nicht.
    Ich habe noch einiges zu lernen.
    Jo.
    rwVMA ist ja vom Typ VertriebMitarbeiterRow. Wie Du ja bereits erfahren hast, hat diese Row Eigenschaften, u.a. die im DataSetDesigner definierten Spalten.
    Und jetzt kommt der Riesenvortal typisierter DataSets zum tragen: Auch eine Eigenschaft GetPlanRows. Das ist keine Zauberei, sonder verweist aufgrund der von Dir im DataSetDesigner eingefügten Relation auf die Datensätze der Tabelle "Plan", in denen "Plan=>VertriebMitarbeiterID" und "VertriebMitarbieter=>ID" den genau gleichen Wert aufweisen.
    Und diese Eigenschaft "GetPlanRows" gibt eben diese dem Mitarbeiter zugeordneten "PlanRows" als Array(of PlanRows) zurück, das aber auch das Interface IEnumerable implementiert. Und dafür existiert eben die Erweiterung "Where", sowie noch etliche andere, die verdammt hilfreich sein können.
    Langsam nachmachen: gib ein (da in Deiner Druckroutine):
    • Dim rwVMA. (Nach dem Punkt eröffnet Intellisense die weiteren Möglichkeiten, eben auch GetPlanRows)
    • rwVMA.GetPlanRows. (nach dem Punkt kommen wiederum Auswahlmöglichkeiten, darunter eban auch Where)
    Ja, und jetzt musst Du Dir nur noch eine Funktion zusammenbauen, die einen logischen Ausdruck zurück gibt, also entweder TRUE oder FALSE. Ud das ist die Bedingung, die Du brauchst. Und das ist immer noch kein LINQ, sondern ein LAMBDA-Ausdruck.
    • Dim rwPlan = rwVMA.GetPlanRows.Where(Function(f) f.Uploaddatum >= dtpVon.Value AndAlso f.Uploaddatum <= dtpBis.Value)
    Dieser Ausdruck gibt ein IEnumerable(of PlanRow) zurück, das wiederum Eigenschaften hat, unter anderem die von Dir benötigte Anzahl
    • Dim rwPlan = rwVMA.GetPlanRows.Where(Function(f) f.Uploaddatum >= dtpVon.Value AndAlso f.Uploaddatum <= dtpBis.Value).Count
    Wie heisst es so schön: Esbraucht unendliche Zeit, um unendliches Wissen zu Erlangen. Ich durfte vor Äonen in einer Physik-Klausur dafür den mathematischen Beweis erbringen ....
    Nur die Benamung ist natürlich kriminell

    us4711 schrieb:

    VB.NET-Quellcode

    1. Dim rwPlan = rwVMA.GetPlanRows.Where(Function(f) f.Uploaddatum >= dtpVon.Value AndAlso f.Uploaddatum <= dtpBis.Value).Count
    Die Variable enthält eine Zahl, und keine PlanRow.
    Damit ist eine - ich schätze - 80%ige Folgefehler-Wahrscheinlichket programmiert. Also dasses dir iwann mal auf die Füße fällt.
    Noch dazu für jmd, dem sowas nicht sofort auffällt.