System.Index.OutOfRangeException Und System.ArgumentNullException bei Datagridview wenn eine Zeile entfernt wird.

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

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

    System.Index.OutOfRangeException Und System.ArgumentNullException bei Datagridview wenn eine Zeile entfernt wird.

    Moin ihr, ich steh schon wieder mal auf Kriegsfus mit einem Datagridview. Nachdem ich nun schon 4 Stunden selbt versucht hab das Problem zu umgehen, frag ich nun doch euch um Hilfe.

    Ich hab ein Datagridview mit 15 Spalten. Dten bekommt das Datagridview aus einer Bindingsource, die ich mit der DBEx fülle.

    Ich möchte das mit in der letzen Spalte (DataGridViewImageColumn) ein kleines Image angezeigt wird, wenn bei dem angezeigten Eintrag ungelesene Informationen vorliegen, zu diesem Zweck habe ich eine kleines Script, das ich an das ListChanged Event der Bindingsorce gebunden habe.

    VB.NET-Quellcode

    1. Private Sub infos(sender As Object, e As EventArgs) Handles bsServiceticket.ListChanged
    2. For Each row As DataGridViewRow In dgvTickets.Rows
    3. Dim count = InfoCount(My.Settings.User, row.Cells("dgvcId").Value)
    4. With row.Cells("dgvcInfo")
    5. If count > 0 Then
    6. .Value = My.Resources.Alert.ToBitmap
    7. .ToolTipText = count
    8. Else
    9. .Value = transparentImage
    10. End If
    11. End With
    12. Next
    13. End Sub
    14. ''' <summary>
    15. ''' Gibt die Anzahl an nichtgelesenen Infos zurük
    16. ''' </summary>
    17. ''' <param name="techkz"></param>
    18. ''' <param name="ticketId"></param>
    19. ''' <returns></returns>
    20. Private Function InfoCount(techkz As String, ticketId As Integer) As Integer
    21. Dim count As Integer = 0
    22. Dim conn As New MySqlConnection
    23. Dim sqlstring As String = ("Select Count(*) as Anzahl FROM db_dispatching.tbl_serviceticket_detail AS a
    24. Left Join(Select * From db_dispatching.tbl_serviceticket_viewed WHERE viewer Like '" & My.Settings.User & "') as b
    25. On a.ticket_detail_ID = b.ticket_detail_ID
    26. WHERE a.ticket_id = " & ticketId & " And id Is Null;")
    27. Try
    28. conn = New MySqlConnection(My.Settings.db_dispatchingConnectionString)
    29. conn.Open()
    30. Dim command As MySqlCommand = New MySqlCommand(sqlstring, conn)
    31. count = command.ExecuteScalar()
    32. conn.Close()
    33. Debug.Print(count)
    34. Catch ex As MySqlException
    35. Debug.Print(ex.ToString())
    36. End Try
    37. Return count
    38. End Function



    Beim Öfnen und erstmaligen befüllen des DataGridViews läuft das alles prima, nur wenn aus dem Datagridview eine Row verschwindet, kommt es erst zu folgender Fehlermeldung

    und danach zu


    Kann mir jemand helfen? Bin etwas verzweifelt.
    Auch ohne Try Cath bekomm ich die selben Fehlermeldungen. Die Function InfoCount funktioniert auch, da bin ich mir sehr sicher, das Problem wird mal wieder mein schonmal vorhandenes sein, das Infos() versucht auf eine Zelle zuzugreifen die nicht mehr existiert.
    Hatt zwischenzeitlich auch mit Invoke versucht, das funtzt besser, wirft dann aber Fehler, das er die Cells dgvcID oder dgvcInfo nicht findet.
    @DianonForce Sieh Dir den Inhalt der betreffenden Variablen an und dann machst Du ein entsprechendes If OBJECT_EXISTS Then da drumherum und feddich.
    Gugst Du Debuggen, Fehler finden und beseitigen
    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!
    Tja, das ist eins der Probleme in die ich beim rumtesten schon reingelaufen bin. Ich sehe im Haltezustand, das row.Index = -1 ist und das 15 Zellen existieren, deren Value aber Nothing ist. Spricht also dafür, das der Datensatz nicht mehr wirklich existent ist. Leider egal was ich bisher versucht habe, scheint es VB nicht klar zu sein. Denn egal ob ich auf value = Nothing oder Index < 0 geprüft hab, das Script ist schön weitergeleaufen. Was ich auch nicht verstehe, wenn ich mir vorher noch ein Debug.Print von row.cells("dgvcInfo").Value ausgeben lasse, bekomm ich schon ne Fehlemeldung in der Ausgabe, trotzdem läuft das Script über alle Prüfungen die mir bekannt sind drüber.

    Ich hab mir auch schon die Rows angeschaut als das Programm noch lief, eine Cells.Name Eigenschaft hab ich nirgens gefunden, einzig eine .ownedColumn, die aber sowohl in funktionierenden Fall als auch beim Fehler bei .Name = dgvcInfo hat. Also scheint der Name ja noch irgendwie da zu sein, ein row.cells(14).Value führt auch erstmal nicht zu einem Fehler. Als ob die Zelle gleichzeitig existiert und eben doch nicht.

    DianonForce schrieb:

    Dten bekommt das Datagridview aus einer Bindingsource,
    Kann es sein, dass Du Zellen über das DGV gelöscht hast?
    Das muss alles über die BindingSource laufen, dann klappt das andere auch.
    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!
    Zellen nein! Die Bindingsource holt mir alle Datensätze mit dem Status 'Ware bestellt' und zeigt mir diese im DGV an. Der Fehler entsteht, wenn ich den Status ändere, der Datensatz also ansich nicht mehr im DGV angezeigt wird, darum hängt das Script auch an bindingsource.ListChange.

    So ein Ähnliches Problem hatte ich schon einmal, dmals mit Hilfe vom Forum und Me.Begininvoke gelöst, wie geschrieben hatte ich das hier auch schon versucht, leider ohne Erfolg.

    Ich hab auch kein anderes Event gefunden, das getriggert wird, wenn sich der Inhalt in dem DGV ändert. Ich hatte es mit DGV.RowAdded versucht, da meckert aber VB das das Objekt noch nicht gezeichnet ist und somit kein Zugriff möglich sei.

    DianonForce schrieb:

    wenn ich den Status ändere, der Datensatz also ansich nicht mehr im DGV angezeigt wird
    Was genau machst Du da?
    Bei einer DataSource wird die neue kundgetan, indem .DataSource = Nothing und dann .DataSource = DIE_NEUE_SOURCE gesetzt wird.
    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!
    Was ich da mache? Ich hab ein Datagridview.CellEndEdit Event, welches über die DBex von ErfinderDesRades erst ein .save macht und dann ein .Fill, d.h. die daten werden neu in die DataTable des Dataset eingelesen, welches die Grundlage der Bindingsource des Datagridview ist.
    Was die DBEx genau macht, ist für mich Magie ;)
    @DianonForce Und an welcher Stelle knallt es da?
    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!
    Ok, back to Anfang.
    Wenn die DBEx die DataTable im Dataset befüllt, löst das Bindingsource.ListChange Event das von mir oben gepostete Script aus, und da knallt es dann. mit obigen Fehlermeldungen. Da Visualstudio mir nix genaueres sagt weiß ich nicht 100% wo genau, aber ich vermute, das das Script beim Zugriff auf die Cell("dgvcInfo") ins leere läuft. Ein If Block um das Script mit

    VB.NET-Quellcode

    1. if not row.cells("dgvcInfo") Is Nothing
    greift aber nicht, was ich nicht verstehe, wen VB die Zelle nicht findet sollte das doch triggern.

    DianonForce schrieb:

    VB.NET-Quellcode

    1. Dim count = InfoCount(My.Settings.User, row.Cells("dgvcId").Value)
    Ich denke, dass es in dieser Zeile knallt, denn wenn die Zelle nicht da ist, gibt es keinen Value.
    Du schreibst zwar was von Bindingsource, Du greifst aber auf das DGV zu.
    Wenn Du Zellen ausliest, solltest Du die Bindingsource bemühen, denn die hält die Daten, das DGV zeigt lediglich an.
    Ein kleiner Test ohne Bindingsource funktioniert so, wie es sein soll.
    Ist bei Dir DGV.AllowUserToAddRows = True?
    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!
    :) Ok, nu wirds kompliziert.
    DGV.AllowUserToAddRows ist false, das DGV dient nur zur Verwaltung bestehender Tickets, nicht zum anlegen neuer.
    Für die "dgvcId" könnte ich vermutlich tatsächlich auf die Bindingsource zugreifen, für die "dgvcInfo" muss ich aber aufs DGV zugreifen, da dies eine ungebundene Spalte im DGV ist und in der BS nicht existiert. Ich vermute es knallt dann hald später, werde es aber sobald ich ein par Stunden Zeit hab testen. Aber wie greife ich dann im DGV auf die der BS entsprechende Row zu?

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

    DianonForce schrieb:

    Aber wie greife ich dann im DGV auf die der BS entsprechende Row zu?
    Gugst Du BindingSource.Current - das wird wohl etwas tricky werden, da Du auf den richtigen Typ casten musst.
    msdn.microsoft.com/de-de/libra…ce.current(v=vs.110).aspx
    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!
    *unnötiges Zitat entfernt*

    Ok, wenn ich das recht verstehe, würde mit BindingSource.Current die aktuelle DataRow aus dem BindingSource zurück geben. Gleiches erreiche ich doch aber auch mit for each row as DataRow in Bindingsource.DataTable.Rows, aber ich find darin nichts was mir recht einfach die Möglichkeit gibt im DGV die selbe Row zu finden, nochmal durch jeder Row des DGV zu gehen und nach der ID zu suchen wäre etwas Overkill. Irgendwie steh ich auf dem Schlauch.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Marcus Gräfe“ ()

    Kleine Zwischenfrage: Hast du den TryCatch denn nu mal entfernt, und weisst du nun, in welcher Zeile es genau knallt?

    Einfach nur, dass das mal geklärt ist.

    Wenn das nicht weiter bringt, wäre als nächstes Code auszukommentieren, und durch herum-probieren genau eingrenzen, ab wann der Fehler wegbleibt.
    Also, Step für Step (Fester Wert anstatt dem Aufruf der InfoCount Funktion)
    folgendes funktioniert ohne Fehler:

    VB.NET-Quellcode

    1. Private Sub infos(sender As Object, e As EventArgs) Handles bsServiceticket.ListChanged
    2. For Each row As DataGridViewRow In dgvTickets.Rows
    3. Dim count = 10
    4. With row.Cells("dgvcInfo")
    5. If count > 0 Then
    6. .Value = My.Resources.Alert.ToBitmap
    7. .ToolTipText = count
    8. Else
    9. .Value = transparentImage
    10. End If
    11. End With
    12. Next
    13. End Sub


    Folgendes funktioniert auch (Random Wert statt der InfoCount Funktion. Ich bin überzeugt das InfoCount immer einen Wert zurück gibt, deswegen dachte ich es liegt vielleicht an den wechselnden Werten)

    VB.NET-Quellcode

    1. Private Sub infos(sender As Object, e As EventArgs) Handles bsServiceticket.ListChanged
    2. For Each row As DataGridViewRow In dgvTickets.Rows
    3. Dim r As Random = New Random
    4. Dim count = r.Next(1, 10)
    5. With row.Cells("dgvcInfo")
    6. If count > 0 Then
    7. .Value = My.Resources.Alert.ToBitmap
    8. .ToolTipText = count
    9. Else
    10. .Value = transparentImage
    11. End If
    12. End With
    13. Next
    14. End Sub


    Ok, sieht im ersten Step danach aus, das InfoCount mein Problem ist, aber wie gesagt, ich bin überzeugt das InfoCount immer einen Wert zurück gibt, deswegen habe ich folgendes Versucht. (ich lasse mir sowohl row.Cells("dgvcId").Value als auch den Return von InfoCount in die Debug Ausgabe ausgeben.)

    VB.NET-Quellcode

    1. Private Sub infos(sender As Object, e As EventArgs) Handles bsServiceticket.ListChanged
    2. For Each row As DataGridViewRow In dgvTickets.Rows
    3. Dim r As Random = New Random
    4. Dim count = InfoCount(My.Settings.User, row.Cells("dgvcId").Value)
    5. Debug.Print(row.Cells("dgvcId").Value)
    6. Debug.Print(count)
    7. With row.Cells("dgvcInfo")
    8. If count > 0 Then
    9. .Value = My.Resources.Alert.ToBitmap
    10. .ToolTipText = count
    11. Else
    12. .Value = transparentImage
    13. End If
    14. End With
    15. Next
    16. End Sub
    17. Private Function InfoCount(techkz As String, ticketId As Integer) As Integer
    18. Dim count As Integer = 0
    19. Dim conn As New MySqlConnection
    20. Dim sqlstring As String = ("Select Count(*) as Anzahl FROM db_dispatching.tbl_serviceticket_detail AS a
    21. Left Join(Select * From db_dispatching.tbl_serviceticket_viewed WHERE viewer Like '" & My.Settings.User & "') as b
    22. On a.ticket_detail_ID = b.ticket_detail_ID
    23. WHERE a.ticket_id = " & ticketId & " And id Is Null;")
    24. 'Try
    25. conn = New MySqlConnection(My.Settings.db_dispatchingConnectionString)
    26. conn.Open()
    27. Dim command As MySqlCommand = New MySqlCommand(sqlstring, conn)
    28. count = command.ExecuteScalar()
    29. conn.Close()
    30. 'Catch ex As MySqlException
    31. 'Debug.Print(ex.ToString())
    32. 'End Try
    33. Return count
    34. End Function


    Als Ergebnis erhalte ich dies. Wie man sieht, zu jeder ID aus jeder DGV.Row gibt es auch ein Return von InfoCount. Die Row mit der ID 30837 habe ich übrigens geändert.
    Spoiler anzeigen
    55633
    0
    54518
    1
    54067
    0
    30837
    0
    56335
    1
    5 Update-Duration: 211,9732 ms
    56331
    1
    56328
    2
    56322
    0
    56320
    2
    56318
    0
    56317
    1
    56304
    0
    56302
    0
    56299
    1
    56288
    2
    56249
    0
    56286
    2
    56083
    2
    55856
    3
    56311
    0
    56191
    2
    56161
    1
    56138
    0
    55464
    0
    56330
    0
    56324
    0
    56306
    0
    56303
    1
    56284
    0
    56254
    0
    56165
    0
    56164
    0
    56147
    2
    56339
    0
    56321
    1
    56309
    0
    56301
    0
    56297
    1
    56206
    1
    56287
    1
    56179
    2
    56167
    4
    56140
    4
    55820
    0
    56197
    0
    55704
    4
    55255
    2
    49811
    5
    56338
    1
    56337
    0
    56333
    0
    56326
    0
    56281
    1
    56278
    0
    56062
    0
    56005
    0
    55826
    0
    55020
    1
    56327
    0
    56325
    0
    56316
    0
    56314
    0
    56310
    0
    56308
    0
    56296
    1
    56276
    1
    56252
    0
    56241
    0
    56001
    0
    56336
    0
    55151
    2
    56029
    0
    54480
    2
    55862
    0
    56030
    0
    55620
    0
    56146
    0
    56334
    0
    56329
    0
    56313
    1
    56307
    0
    56293
    2
    56264
    1
    56188
    0
    56171
    0
    56163
    1
    56115
    0
    56093
    0
    56092
    2
    56037
    1
    55975
    0
    55967
    0
    55874
    2
    55834
    0
    55818
    0
    55273
    2
    55266
    1
    53948
    0
    53266
    0
    56340
    0
    56323
    0
    56300
    0
    56277
    0
    56269
    0
    56245
    0
    56244
    0
    56227
    0
    56219
    1
    56185
    0
    56176
    0
    56109
    0
    56094
    0
    56079
    0
    56061
    0
    55899
    0
    55716
    0
    55182
    1
    55954
    0
    55827
    1
    55493
    0
    55334
    1
    54886
    1
    54885
    3
    54823
    0
    54698
    0
    54604
    2
    53768
    4
    53326
    3
    53318
    0
    53094
    1
    53076
    1
    52977
    2
    52422
    1
    51955
    0
    51953
    0
    51952
    3
    46858
    8
    56312
    1
    56275
    1
    56260
    0
    56233
    0
    55824
    0
    55727
    0
    55684
    0
    55586
    0
    55518
    0
    55463
    0
    54389
    0
    51341
    0
    48800
    0
    45994
    0
    55633
    0
    54518
    1
    54067
    0


    Da der Fehler aber nur entsteht, wenn InfoCount auch aufgerufen wird muß der Fehler ja damit zusammenhängen. Da InfoCount ja nachweißlich immer einen Wert zurück gbt, kann es wohl eher nicht mit der dem Ergebniss der Funktion zu tun haben.
    Wenn ich mir überlege was InfoCount macht, eine Verbindung zu der Datenbank aufbauen, eine Abfrage durchführen und das Ergebniss zurückgeben, sehe ich auch nicht wo da das Problem herkommen soll. Datenbankverbindung und Abfrage funktionieren anscheinend da ich ja Werte zurück bekomme.
    Ich vermute mal das in der Zeit in der die Funktion läuft sich irgendetwas am DGV ändert, so das danach ein Zugriff auf DataGridViewRow nicht mehr klappt. Ein ähnliches Problem hatte ich mit der Datenaktualisiereung nach einem DataGridView.CellEndEdit Event hier schonmal.
    Da damals die Lösung ein Me.BeginInvoke war, dachte ich es hier auch damit zu versuchen kann nicht schaden.

    VB.NET-Quellcode

    1. Private Sub infos(sender As Object, e As EventArgs) Handles bsServiceticket.ListChanged
    2. For Each row As DataGridViewRow In dgvTickets.Rows
    3. BeginInvoke(Sub(r As DataGridViewRow)
    4. Dim count = InfoCount(My.Settings.User, r.Cells("dgvcId").Value)
    5. Debug.Print(r.Cells("dgvcId").Value)
    6. Debug.Print(count)
    7. With r.Cells("dgvcInfo")
    8. If count > 0 Then
    9. .Value = My.Resources.Alert.ToBitmap
    10. .ToolTipText = count
    11. Else
    12. .Value = transparentImage
    13. End If
    14. End With
    15. End Sub, row)
    16. Next
    17. End Sub

    Nun bekomm ich nichtmehr die obigen beiden Fehlerfenster, sondern der Debuger schmeist mir folgendes entgegen:

    Quellcode

    1. Eine Ausnahme vom Typ "System.ArgumentException" ist in System.Windows.Forms.dll aufgetreten, doch wurde diese im Benutzercode nicht verarbeitet.
    2. Zusätzliche Informationen: Die Spalte dgvcId kann nicht gefunden werden.

    wenn ich mir r anschaue, hat Cells einen Count von 15, die 1. ist normalerweise dgvcId, also die, die VB angeblich nicht findet. Schaue ich mir Cells.List an so ist finde ich in {0} folgendes

    Quellcode

    1. OwningColumn = {DataGridViewTextBoxColumn { Name=dgvcId, Index=0 }}
    Ist das jetzt dgvcId oder nicht? (Also ich hab sie gefunden, warum VB nicht?)
    Ok, Computer sind manchmal nicht so kreativ beim herstellen von Kontexten, vielleicht, sucht er ja irgendwie anderes als ich die DGVCInfo.
    Versuche ich es hald mit r.Cells(0).Value anstatt mit r.Cells("dgvcId").Value.
    Ok, ähnliches Spiel einen CellsAufruf später, diesmal findet VB angeblich dgvcInfo bei With r.Cells("dgvcInfo") nicht. Ok, in r.Cells.List bei {14} geschaut

    Quellcode

    1. OwningColumn = {DataGridViewImageColumn { Name=dgvcInfo, Index=14 }}
    Ok, hab ich erwartet.
    OK, mach ich VB hald den Gefallen und ändere With r.Cells("dgvcInfo") in With r.Cells(14")
    Nun bekomm ich wieder die 2. Fehlermeldung angezigt.

    Sorry für die Wall of Text, ich wollte es nur mal der vollständigkeit posten, da ich das Gefühl hatte, man legt mir nahe ich hätte kein Debugging versucht, bzw nicht versucht den Code in Teilen auszuschließen.

    Ob das mit dem Invoke nun Sinn macht oder nicht, weis ich nicht, das ganze Spiel hatte ich auch schon gemacht bevor ich hier den ersten Post gemacht hab. Leider haben mich alle Versuche soweit kaum bis garnicht witergebracht. Ich hab nun noch ein par Zeilen Code mehr drin, bekomme aber immer ncoh kein klares Bild warum VB der Meinung ist eine Fehlermeldung zu bringen, auch bringt die Info die in der Fehlermeldung steht, zumnidest mich nicht weiter.

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

    DianonForce schrieb:

    VB.NET-Quellcode

    1. BeginInvoke(Sub(r As DataGridViewRow)
    Das ist ein Lambda-Ausdruck, da kann ich Dur nur von abraten, in solch ein Ding mehrere Zeilen Code zu schreiben, die verhalten sich manchmal merkwürdig und lassen sich NICHT debuggen!
    Um die vielen Zeilen mit Zajlen in Deinem Post mach einen , editiere bitte Deinen Post.
    Die Zeile Dim r As Random = New Random packst Du außerhalb der äußeren Schleife, damit Du tatsächlich halbwegs zufällige Zahlen bekommst.
    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!

    DianonForce schrieb:

    den großen Unterschied
    das war der Lambda-Ausdruck.
    ===========
    Random - Teste dies:

    VB.NET-Quellcode

    1. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    2. ListBox1.Items.Clear()
    3. For i = 1 To 10
    4. Dim rnd = New Random
    5. ListBox1.Items.Add(rnd.Next(1, 10))
    6. Next
    7. End Sub
    8. Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
    9. ListBox1.Items.Clear()
    10. Dim rnd = New Random
    11. For i = 1 To 10
    12. ListBox1.Items.Add(rnd.Next(1, 10))
    13. Next
    14. End Sub
    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!