Zufällig erstellte ListView drucken - Argument out of range exception-Fehler

  • VB.NET

Es gibt 15 Antworten in diesem Thema. Der letzte Beitrag () ist von Filmer.

    Zufällig erstellte ListView drucken - Argument out of range exception-Fehler

    Liebes Forum,

    ich versuche nun schon seit längerer Zeit, eine "zufällig" (das heißt eine immer unterschiedlich lange) ListView auszudrucken. Alle Codes, die ich bis jetzt im Internet gefunden habe, funktionieren bei mir leider nicht.
    Dann habe ich folgenden Code gefunden:
    Einmal ein Class-Modul:

    VB.NET-Quellcode

    1. Imports System.Drawing
    2. Imports System.Windows.Forms
    3. Public Class PrintListView
    4. Private LV As ListView
    5. Private SpaltenBreite As New List(Of Integer)
    6. Private TextHöhe As Integer
    7. Private OffsetSpalte As Integer
    8. Private OffsetZeile As Integer
    9. Private MerkerSpalte As Integer
    10. Private MerkerZeile As Integer
    11. Public HeaderColor As System.Drawing.Color = Color.LightGray
    12. Private WithEvents PD As New System.Drawing.Printing.PrintDocument
    13. Private PrintPrev As New System.Windows.Forms.PrintPreviewDialog
    14. Private asc As SizeColumn = SizeColumn.None
    15. Public Enum SizeColumn
    16. None
    17. ScretchColumn
    18. AutoSitze
    19. End Enum
    20. Public Property AutoSizeColumn() As SizeColumn
    21. Get
    22. Return asc
    23. End Get
    24. Set(ByVal value As SizeColumn)
    25. asc = value
    26. SizeColums()
    27. End Set
    28. End Property
    29. Public Property Landscape() As Boolean
    30. Get
    31. Return PD.DefaultPageSettings.Landscape
    32. End Get
    33. Set(ByVal value As Boolean)
    34. PD.DefaultPageSettings.Landscape = value
    35. SizeColums()
    36. End Set
    37. End Property
    38. Private Sub SizeColums()
    39. Dim breite As Integer
    40. Dim g As Graphics = LV.CreateGraphics
    41. Dim zähler As Integer
    42. SpaltenBreite.Clear()
    43. Select Case asc
    44. Case SizeColumn.None, SizeColumn.ScretchColumn
    45. For Each CH As Windows.Forms.ColumnHeader In LV.Columns
    46. SpaltenBreite.Add(CH.Width)
    47. Next
    48. Case SizeColumn.AutoSitze, SizeColumn.ScretchColumn
    49. If asc = SizeColumn.AutoSitze Then
    50. For Each CH As Windows.Forms.ColumnHeader In LV.Columns
    51. breite = g.MeasureString(CH.Text, LV.Font).Width + 20
    52. SpaltenBreite.Add(breite)
    53. Next
    54. End If
    55. For Each LVI As ListViewItem In LV.Items
    56. zähler = 0
    57. breite = g.MeasureString(LVI.Text, LV.Font).Width + 20
    58. If asc = SizeColumn.AutoSitze Then SpaltenBreite.Add(breite)
    59. If SpaltenBreite(zähler) + 20 < breite Then SpaltenBreite(zähler) = breite
    60. For Each LVSI As ListViewItem.ListViewSubItem In LVI.SubItems
    61. breite = g.MeasureString(LVSI.Text, LV.Font).Width + 20
    62. If SpaltenBreite(zähler) + 20 < breite Then SpaltenBreite(zähler) = breite
    63. zähler += 1
    64. Next
    65. Next
    66. End Select
    67. End Sub
    68. Public Sub New()
    69. End Sub
    70. Public Sub New(ByVal ListViewToPrint As ListView)
    71. LV = ListViewToPrint
    72. Dim g As Graphics = LV.CreateGraphics
    73. TextHöhe = g.MeasureString("XyZ1!", LV.Font).Height + 5
    74. SizeColums()
    75. SpaltenBreite.Add(0)
    76. g.Dispose()
    77. End Sub
    78. Public Sub Print()
    79. PD.Print()
    80. End Sub
    81. Public Sub Preview()
    82. PrintPrev.Document = PD
    83. PrintPrev.WindowState = FormWindowState.Maximized
    84. PrintPrev.ShowDialog()
    85. End Sub
    86. Private Sub PD_PrintPage(ByVal sender As Object, ByVal e As System.Drawing.Printing.PrintPageEventArgs) Handles PD.PrintPage
    87. e.Graphics.SmoothingMode = Drawing2D.SmoothingMode.AntiAlias
    88. e.Graphics.TextRenderingHint = Drawing.Text.TextRenderingHint.AntiAlias
    89. Dim left As Decimal = PD.DefaultPageSettings.Margins.Left
    90. Dim right As Decimal = PD.DefaultPageSettings.Margins.Right
    91. Dim top As Decimal = PD.DefaultPageSettings.Margins.Top
    92. Dim bottom As Decimal = PD.DefaultPageSettings.Margins.Bottom
    93. Dim PageWidth As Integer = PD.DefaultPageSettings.Bounds.Width - (right + left)
    94. Dim PageHeight As Decimal = PD.DefaultPageSettings.Bounds.Height - (top + bottom)
    95. Dim sf As New StringFormat
    96. sf.Alignment = StringAlignment.Near
    97. sf.LineAlignment = StringAlignment.Center
    98. Dim rf As New Rectangle
    99. Dim br As SolidBrush
    100. Dim br1 As SolidBrush
    101. Dim PosX As Integer = left
    102. Dim PosY As Integer = top
    103. Dim OffsetSpalte As Integer
    104. Dim OffsetZeile As Integer
    105. ' Header schreiben
    106. Do
    107. rf = New Rectangle(PosX, PosY, SpaltenBreite(OffsetSpalte + MerkerSpalte), TextHöhe)
    108. e.Graphics.FillRectangle(New SolidBrush(HeaderColor), rf)
    109. If LV.GridLines Then e.Graphics.DrawRectangle(Pens.Black, rf.X, rf.Y, rf.Width, rf.Height)
    110. e.Graphics.DrawString(LV.Columns(OffsetSpalte + MerkerSpalte).Text, LV.Font, Brushes.Black, rf, sf)
    111. PosX += SpaltenBreite(OffsetSpalte + MerkerSpalte)
    112. OffsetSpalte += 1
    113. Loop Until PageWidth + left < PosX + SpaltenBreite(OffsetSpalte + MerkerSpalte) Or OffsetSpalte + MerkerSpalte > LV.Columns.Count - 1
    114. PosX = left
    115. OffsetSpalte = 0
    116. OffsetZeile = 0
    117. Do
    118. OffsetZeile = 0
    119. PosY = top + TextHöhe
    120. Do
    121. If (LV.Items(OffsetZeile + MerkerZeile).SubItems.Count > OffsetSpalte + MerkerSpalte) Then
    122. rf = New Rectangle(PosX, PosY, SpaltenBreite(OffsetSpalte + MerkerSpalte), TextHöhe)
    123. If LV.Items(OffsetZeile + MerkerZeile).UseItemStyleForSubItems = True Then
    124. br = New SolidBrush(LV.Items(OffsetZeile + MerkerZeile).BackColor)
    125. br1 = New SolidBrush(LV.Items(OffsetZeile + MerkerZeile).ForeColor)
    126. Else
    127. br = New SolidBrush(LV.Items(OffsetZeile + MerkerZeile).SubItems(OffsetSpalte + MerkerSpalte).BackColor)
    128. br1 = New SolidBrush(LV.Items(OffsetZeile + MerkerZeile).SubItems(OffsetSpalte + MerkerSpalte).ForeColor)
    129. End If
    130. e.Graphics.FillRectangle(br, rf)
    131. If LV.GridLines Then e.Graphics.DrawRectangle(New Pen(LV.ForeColor), rf)
    132. Select Case LV.Columns(OffsetSpalte + MerkerSpalte).TextAlign
    133. Case HorizontalAlignment.Center
    134. sf.Alignment = StringAlignment.Center
    135. Case HorizontalAlignment.Left
    136. sf.Alignment = StringAlignment.Near
    137. Case HorizontalAlignment.Right
    138. sf.Alignment = StringAlignment.Far
    139. End Select
    140. e.Graphics.DrawString(LV.Items(OffsetZeile + MerkerZeile).SubItems(OffsetSpalte + MerkerSpalte).Text, LV.Font, br1, rf, sf)
    141. End If
    142. PosY += TextHöhe
    143. OffsetZeile += 1
    144. Loop Until PageHeight + top < PosY + TextHöhe Or OffsetZeile + MerkerZeile >= LV.Items.Count
    145. PosX += SpaltenBreite(OffsetSpalte + MerkerSpalte)
    146. OffsetSpalte += 1
    147. Loop Until PageWidth + left < PosX + SpaltenBreite(OffsetSpalte + MerkerSpalte) Or OffsetSpalte + MerkerSpalte >= LV.Columns.Count
    148. If OffsetSpalte + MerkerSpalte = LV.Columns.Count And OffsetZeile + MerkerZeile = LV.Items.Count Then
    149. e.HasMorePages = False
    150. MerkerZeile = 0
    151. MerkerSpalte = 0
    152. OffsetSpalte = 0
    153. OffsetZeile = 0
    154. Exit Sub
    155. End If
    156. If OffsetZeile + MerkerZeile < LV.Items.Count Then
    157. MerkerZeile = OffsetZeile + MerkerZeile
    158. e.HasMorePages = True
    159. Exit Sub
    160. End If
    161. If MerkerSpalte = OffsetSpalte < LV.Columns.Count Then
    162. MerkerSpalte = OffsetSpalte + MerkerSpalte
    163. MerkerZeile = 0
    164. e.HasMorePages = True
    165. Exit Sub
    166. End If
    167. End Sub
    168. End Class


    Und der zugehörige Form-Code:

    VB.NET-Quellcode

    1. Private PrintListView As New WindowsApplication1.PrintListView
    2. Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    3. ' Listview mit "Daten" füllen...
    4. ListView1.View = View.Details
    5. Dim x As Integer
    6. Dim y As Integer
    7. For x = 0 To 15
    8. ListView1.Columns.Add("Spalte" & x.ToString)
    9. Next
    10. ListView1.Columns(5).TextAlign = HorizontalAlignment.Right
    11. ListView1.Columns(5).Width = 200
    12. For y = 0 To 40
    13. ListView1.Items.Add("Zeile" & y.ToString & " / Spalte1")
    14. If y Mod 2 = 0 Then ListView1.Items(y).BackColor = Color.LightGray
    15. For x = 1 To 15
    16. ListView1.Items(y).SubItems.Add("Zeile" & y.ToString & " / Spalte" & x.ToString)
    17. Next
    18. Next
    19. ListView1.Items(3).ForeColor = Color.Blue
    20. ListView1.Items(7).UseItemStyleForSubItems = False
    21. ListView1.Items(7).SubItems(1).ForeColor = Color.Red
    22. ListView1.GridLines = True
    23. PrintListView = New WindowsApplication1.PrintListView(ListView1)
    24. PrintListView.AutoSizeColumn = PrintListView.SizeColumn.AutoSitze
    25. PrintListView.HeaderColor = Color.LightBlue
    26. End Sub
    27. Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    28. ' Vorschau anzeigen.... und drucken...
    29. PrintListView.Preview()
    30. End Sub
    31. Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
    32. ' ohne Vorschau drucken
    33. PrintListView.Print()
    34. End Sub


    Mit diesem Beispiel funktioniert alles wunderbar. Doch sobald ich den "Form-Load"-Teil raus nehme und meine eigene ListView drucken möchte, kommt der Fehler "Argument out of range exception", welcher sich im Class-Code auf "rf = New Rectangle(PosX, PosY, SpaltenBreite(OffsetSpalte + MerkerSpalte), TextHöhe)" (Zeile 138) bezieht.

    Bevor jetzt diverse Sätze kommen wie "Nutze die Suchfunktion"; das habe ich bereits gemacht, allerdings ohne Erfolg. Auch Google hat mir nicht wirklich weitergeholfen. :(

    Ich hoffe, ihr könnt mir helfen.

    Vielen Dank im Voraus,
    Filmer
    Willkommen im Forum. :thumbup:

    Filmer schrieb:

    Doch sobald ich den "Form-Load"-Teil raus nehme und meine eigene ListView drucken möchte
    Was genau muss ich tun, um dies nachzuvollziehen?
    Aus dieser Zeile werde ich nicht schlau:

    VB.NET-Quellcode

    1. If MerkerSpalte = OffsetSpalte < LV.Columns.Count Then
    Gib bitte Deinem Projekt Option Strikt On und korrigiere die Fehler, die da angezeigt werden.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Danke :)
    Also wenn das Projekt lädt, füllt es die ListView automatisch mit Inhalt. Das wollte ich unterbinden, weil in der ListView meine eigenen Werte stehen sollten. Deswegen habe ich diesen Teil gelöscht (bzw. in einem anderen Versuch die Auto-Füllen-Funktion auf einen Button verlegt, was auch super klappt).
    Beim "Option Strikt On" passiert auch nichts. Es kommt nur die selbe Fehlermeldung.

    Was

    VB.NET-Quellcode

    1. If MerkerSpalte = OffsetSpalte < LV.Columns.Count Then

    bedeutet, ändert, etc. weiß ich leider auch nicht. Da ich noch relativ am Anfang von Visual Basic stehe, war ich froh, diesen Code im Internet gefunden zu haben.

    VB.NET-Quellcode

    1. rf = New Rectangle(PosX, PosY, SpaltenBreite(OffsetSpalte + MerkerSpalte), TextHöhe)
    Mach mal das und poste mal bitte die beiden letzten Werte, die vor der Fehlermeldung auftreten

    VB.NET-Quellcode

    1. MessageBox.Show((OffsetSpalte + MerkerSpalte).ToString)
    2. MessageBox.Show((SpaltenBreite.Count - 1).ToString)
    3. rf = New Rectangle(PosX, PosY, SpaltenBreite(OffsetSpalte + MerkerSpalte), TextHöhe)



    VB.NET-Quellcode

    1. If MerkerSpalte = OffsetSpalte < LV.Columns.Count Then
    Da ist eindeutig irgendwas schief gegangen, versuch mal, entweder das "=" oder das "<" durch verschiedene Rechenoperationen zu ersetzen (plus, minus, mal, geteilt).

    VB.NET-Quellcode

    1. rf = New Rectangle(PosX, PosY, SpaltenBreite(OffsetSpalte + MerkerSpalte), TextHöhe)

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

    Die Werte sind "0" und "-1" wenn ich selbst zwei Werte hinein schreibe und beim Auto-Füllen "0", "58", "1", "58", "2", "58", "3", "58", ...
    Vielleicht sollte ich noch sagen, dass es funktioniert, wenn ich die Liste automatisch füllen lasse und zusätzlich meine eigenen Werte eintrage.
    Mit plus, minus, ... hat es leider auch nicht geholfen.
    Ok, jetzt versteh ich nichts mehr :(
    Wenn du ein Objekt mit dem Index 16 (das wäre die logische nächste Abfrage, die dann den Fehler wirft) in einer List abfragst, die bis Index 58 geht, kann es doch keine ArgumentOutOfRangeException geben??? Oder ich suche den Fehler an der falschen Stelle. Bei welchem Argument wird denn die Fehlermeldung ausgespuckt?
    Nein, bei dem "17" "58" kommt keine Fehlermeldung. Das ist die Liste, die sich automatisch füllt und auch funktioniert. Wenn ich selbst mittels zweier Textboxen Werte eintrage, geben die MessageBoxen die Werte "0" und "-1" aus. Dann kommt die Fehlermeldung.
    @Filmer: Dein Programm knallt, wenn die List(Of T) Spaltenbreite keine Elemente zur Anzeige hat.
    Eine leere Tabelle hat keine Spalten, Du greifst jedoch auf den Index 0 zu:

    VB.NET-Quellcode

    1. rf = New RectangleF(PosX, PosY, SpaltenBreite(OffsetSpalte + MerkerSpalte), TextHöhe)
    Du solltest die Sub PD_PrintPage() verlassen ohne etwas zu tun, wenn keine Spalten da sind.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!

    Filmer schrieb:

    Sollte ich eine Ture/False-Abfrage einfügen?
    Genau, etwa so:

    VB.NET-Quellcode

    1. If SpaltenBreite.Count = 0 Then
    2. Return
    3. End If
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Ich habe diese jetzt direkt an den Anfang der Sub PD_PrintPage() gesetzt. Die Fehlermeldung ist weg! Vielen Dank!
    :)
    Allerdings wird in der Seitenvorschau nichts angezeigt, obwohl ich Werte eingegeben habe. Was muss ich jetzt noch ändern?

    Filmer schrieb:

    Was muss ich jetzt noch ändern?
    Du musst Deinen Code mal ordentlich debuggen, setz einen Haltepunkt rein und verfolge, was passiert, wenn Du ihn schrittweise abarbeitest.
    Verhält sich der Code anders als es Dir vorschwebt, hast Du einen Fehler gefunden.
    Du musst Dich für jede einzelne Zeile Deines Codes davon überzeugen, dass sie so arbeitet, wie sie es soll.
    Eine nicht getestete Zeile Code ist falsch.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    So, ich habe zuerst versucht, den Code zu debuggen, wie RodFromGermany es vorgeschlagen hat. Allerdings habe ich nach kurzer Zeit aufgegeben. Dann kam mir aber eine Idee: Ich sag dem Code, dass er die ListView mit 0 Spalten und 0 Zeilen füllen soll. Das klappte natürlich nicht.
    Also habe ich am Ende des Auto-Füllen-Codes ein "ListView1.Items.Clear()" gesetzt, dann die Spaltenanzahl von 15 auf meine benötigten 6 heruntergesetzt und im Klassenmodul den Codeteil "SpaltenBreite.Clear()" gelöscht, damit meine eigenen Spaltenbreiten erhalten bleiben, was allerdings noch nicht so optimal funktioniert :huh: :)

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