none
Mit einer ForEach-Methode datagridview.Columns durchlaufen! RRS feed

  • Frage

  • Guten Tag die Damen und Herren,
    ich hätte mal eine kleine (Verständnis)-Frage!

    Ausgangspunkt:
    Ich habe ein Datagridview, welches 5 Spalten hat, wobei die ersten 2 Spalten nicht editierbar sein sollen.

    Das ist meine Lösung:

    d_datagridview.Columns(0).ReadOnly = True
    d_datagridview.Columns(1).ReadOnly = True
    d_datagridview.Columns(2).ReadOnly = False
    d_datagridview.Columns(3).ReadOnly = False
    d_datagridview.Columns(4).ReadOnly = False
    

    Sowas möchte ich haben:

    Array.ForEach(d_datagridview.Columns, SetProperty)
    
    Private Sub SetProperty(ByVal column As DataGridViewColumn)
       'hier sollte auch code drin stehen, aber was für einer?
    End Sub
    

    Hat vielleicht jemand hierfür eine schicke Lösung?

     

    Danke im Voraus.

    Mittwoch, 13. April 2011 07:24

Antworten

  • Hallo Jo,

    das wäre, wenn man denn Array.ForEach nutzen möchte:

        Array.ForEach(
          Me.dataGridView1.Columns.Cast(Of DataGridViewColumn).ToArray(),
          Sub(c)
            c.ReadOnly = CBool(IIf(c.DisplayIndex > 1, False, True))
          End Sub)
    
    

    womit der die Sub den Code Deiner angedeuteten SetMethod darstellen würde.

    Für den ersten Parameter gilt:
    Weil kein Array vorliegt, muss man sich eines Erzeugen, was mit der Linq Erweiterungsmethoe ToArray geschieht.
    Da eine DataGridViewCollection kein typisiertes IEnumerable(Of DataGridViewColumn) liefert, ist zuvor noch
    eine LINQ Cast Operation erforderlich (bei Windows Forms oft erforderlich, da ohne Generika implementiert).

    Was dann summa sumarum dem Ganzen deutlich mehr Overhead verpasst, als es die gezeigte "normale" Variante hat.

    Sinnvollere Einsatzgebiete wären eher Bereiche, wo man mit generischen Auflistungen wie List(Of T) arbeitet.
    Wenn es Dich näher interessiert, solltest Dich mit LINQ beschäftigen, wo das häufiger zum Einsatz kommt.
    Siehe z. B. Linq - Summierung von mehreren Spalten, wo das verwendete gruppe.Sum(Function(w) w.Wert[1..4])
    konzeptionell das gleiche ist.

    Gruß Elmar

    Donnerstag, 14. April 2011 08:17
    Beantworter
  •  

    Hallo,

    mit Array.ForEach wird das schon mal nicht klappen, da es sich bei der Columns-Eigenschaft um eine Auflistung handelt (und kein Array).

    Allgemein betrachtet:
    In einem Enumerator - und in der Hinsicht unterscheidet sich Array/List.ForEach nicht von der For Each-Anweisung von Visual Basic -
    hast Du keine Möglichkeit über einen Index zuzugreifen, da eine Position nicht bereitgestellt wird.
    Enumeratoren - repräsentiert über die IEnumerable(Of T)  bzw. IEnumerable Schnittstelle sind die Vorläufer
    einer Auflistung - respräsentiert über IList(Of T) bzw. IList und erst ist eine Position (über den Index).

    Weswegen man in den Fällen, wo die Index-Position entscheidend ist, besser über eine For Schleife zugreift.

    Spezieller betrachtet:
    Hier könnte man auf Eigenschaften wie DisplayIndex zurückgreifen, was aber nicht das gleiche wie die Position in der Auflistung ist
    (sondern die aktuelle Anordnung der Spalte angibt und sich u. U. ändern könnte).

    Aber der Einsatz eines Delegaten lohnt für diesen Einsatzzweck insgesamt nicht, da man über

    ' Optimist: Voreinstellung ist False
    For columIndex = 0 To 1
      d_datagridview.Columns(columIndex).ReadOnly = True
    Next
    
    ' oder für Pessimisten:
    For columIndex = 0 To d_datagridview.Columns.Count - 1
      d_datagridview.Columns(columIndex).ReadOnly = IIf(columnIndex > 1, False, True)
    Next
    

    auf kürzerem Wege zu Ziel kommt - das ist zwar nicht so "schick" aber funktional.
    Letztere Version braucht man nur, wenn ReadOnly wechselhaft ist - Voreinstellung ist dort ohnehin False,
    zumindest solange die Datenquelle überhaupt bearbeitbar ist.

    Im allgemeinen würde ich eh keine Methode mehr implementieren sondern gleich einen Lamba-Ausdrucks verwenden
    und den Compiler die Arbeit überlassen, so z. B.

    Sub(c) c.ReadOnly = IIf(c.DisplayIndex > 1, False, True) End Sub
    
    (was wie oben geschrieben jedoch nicht identisch ist).

    Und wenn Dir was aus Deinem Umfeld einfällt, wo man das sinnvoller einsetzen kann,
    gebe ich Dir auch gerne ein funktionierendes Beispiel.

    Gruß Elmar

    Mittwoch, 13. April 2011 08:17
    Beantworter

Alle Antworten

  •  

    Hallo,

    mit Array.ForEach wird das schon mal nicht klappen, da es sich bei der Columns-Eigenschaft um eine Auflistung handelt (und kein Array).

    Allgemein betrachtet:
    In einem Enumerator - und in der Hinsicht unterscheidet sich Array/List.ForEach nicht von der For Each-Anweisung von Visual Basic -
    hast Du keine Möglichkeit über einen Index zuzugreifen, da eine Position nicht bereitgestellt wird.
    Enumeratoren - repräsentiert über die IEnumerable(Of T)  bzw. IEnumerable Schnittstelle sind die Vorläufer
    einer Auflistung - respräsentiert über IList(Of T) bzw. IList und erst ist eine Position (über den Index).

    Weswegen man in den Fällen, wo die Index-Position entscheidend ist, besser über eine For Schleife zugreift.

    Spezieller betrachtet:
    Hier könnte man auf Eigenschaften wie DisplayIndex zurückgreifen, was aber nicht das gleiche wie die Position in der Auflistung ist
    (sondern die aktuelle Anordnung der Spalte angibt und sich u. U. ändern könnte).

    Aber der Einsatz eines Delegaten lohnt für diesen Einsatzzweck insgesamt nicht, da man über

    ' Optimist: Voreinstellung ist False
    For columIndex = 0 To 1
      d_datagridview.Columns(columIndex).ReadOnly = True
    Next
    
    ' oder für Pessimisten:
    For columIndex = 0 To d_datagridview.Columns.Count - 1
      d_datagridview.Columns(columIndex).ReadOnly = IIf(columnIndex > 1, False, True)
    Next
    

    auf kürzerem Wege zu Ziel kommt - das ist zwar nicht so "schick" aber funktional.
    Letztere Version braucht man nur, wenn ReadOnly wechselhaft ist - Voreinstellung ist dort ohnehin False,
    zumindest solange die Datenquelle überhaupt bearbeitbar ist.

    Im allgemeinen würde ich eh keine Methode mehr implementieren sondern gleich einen Lamba-Ausdrucks verwenden
    und den Compiler die Arbeit überlassen, so z. B.

    Sub(c) c.ReadOnly = IIf(c.DisplayIndex > 1, False, True) End Sub
    
    (was wie oben geschrieben jedoch nicht identisch ist).

    Und wenn Dir was aus Deinem Umfeld einfällt, wo man das sinnvoller einsetzen kann,
    gebe ich Dir auch gerne ein funktionierendes Beispiel.

    Gruß Elmar

    Mittwoch, 13. April 2011 08:17
    Beantworter
  • Vielen Dank für deine Antwort.

    Dieser Lambda-Ausdruck mit dem DisplayIndex klingt interessant. Wie sähe denn das funktionierende Beispiel aus? :)

     

    Gruß Jo

    Donnerstag, 14. April 2011 07:02
  • Hallo Jo,

    das wäre, wenn man denn Array.ForEach nutzen möchte:

        Array.ForEach(
          Me.dataGridView1.Columns.Cast(Of DataGridViewColumn).ToArray(),
          Sub(c)
            c.ReadOnly = CBool(IIf(c.DisplayIndex > 1, False, True))
          End Sub)
    
    

    womit der die Sub den Code Deiner angedeuteten SetMethod darstellen würde.

    Für den ersten Parameter gilt:
    Weil kein Array vorliegt, muss man sich eines Erzeugen, was mit der Linq Erweiterungsmethoe ToArray geschieht.
    Da eine DataGridViewCollection kein typisiertes IEnumerable(Of DataGridViewColumn) liefert, ist zuvor noch
    eine LINQ Cast Operation erforderlich (bei Windows Forms oft erforderlich, da ohne Generika implementiert).

    Was dann summa sumarum dem Ganzen deutlich mehr Overhead verpasst, als es die gezeigte "normale" Variante hat.

    Sinnvollere Einsatzgebiete wären eher Bereiche, wo man mit generischen Auflistungen wie List(Of T) arbeitet.
    Wenn es Dich näher interessiert, solltest Dich mit LINQ beschäftigen, wo das häufiger zum Einsatz kommt.
    Siehe z. B. Linq - Summierung von mehreren Spalten, wo das verwendete gruppe.Sum(Function(w) w.Wert[1..4])
    konzeptionell das gleiche ist.

    Gruß Elmar

    Donnerstag, 14. April 2011 08:17
    Beantworter