public class JahresTabelle
{
public String Kunde { get; set; }
public String Projekt { get; set; }
public List<Double> Volumen;
}
Daraus erzeuge ich eine Liste:
public List<JahresTabelle> UmsatzJahresTabelle = new List<JahresTabelle>();
Wobei Volumen eine undefinierte Anzahl von Elementen (Anzahl Jahre) darstellt. Das kann von 1 bis 40 alles sein. Wichtig: die Anzahl aller Elemente der Liste Volumen sind immer gleich viele, können aber von Prozedurdurchlauf zu Durchlauf variieren. Deshalb brauche ich eine Variabilität in der Darstellung:
Nun möchte ich diese Liste an mein WPF DataGrid binden. Habe allerdings keine Ahnung wie (oder ob das überhaupt) gehen kann.
Vielleicht habe ich auch den falschen Lösungsweg gewählt?
Für ein einzelnes Element eines Arrays (bzw. einer List<T>) geht dies z.B. mit
{Binding Volumen[0]}
Du müßtest also (am besten per Schleife im Codebehind) die einzelnen Spalten erzeugen und entsprechend den Index zuweisen.
Ich weiß nicht, was passiert, wenn es den Index nicht gibt (also evtl. jeweils per Durchlauf mit passender Arraygröße erzeugen).
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von Th69 am .
Mir ist nicht ganz klar, wie das Ergebnis aussehen soll oder darf:
Kunde 1 | Projekt 1 | [44,5] [2,3] [0,8]
Kunde 1 | Projekt 2 | [2,3] [4,5] [9,8] [3,3]
Kunde 2 | Projekt 1 | [9,8] [2,5]
oder eher so?
Kunde 1 | Projekt 1 | 44,5
Kunde 1 | Projekt 1 | 2,3
Kunde 1 | Projekt 1 | 0,8
Kunde 1 | Projekt 2 | 2,3
Kunde 2 | Projekt 2 | 4,5
Kunde 2 | Projekt 2 | 9,8
Kunde 2 | Projekt 2 | 3,3
usw...
Hallo,
mir ist klar, dass es so nicht funktionieren kann, habe aber keine bessere Idee. Deshalb hier mal der Code.
Irgendwie muss ich eine Structure oder Class mit Properties für die einzelnen Spalten von "Volumen" erstellen. Aber wie?
Ein nachträgliches Anfügen von Spalten macht hier einfach keinen Sinn.
Bin planlos...
Ich verstehe immer noch nicht ganz wie das aussehen soll, aber mein erster Gedanke ging in diese Richtung (vor meinem eigentlichen Job schnell getippt
public class JahresTabelle : ObservableCollection<VolumeDetail>
{
public JahresTabelle(string kunde, string projectName)
{
Kunde = kunde;
ProjektName = projectName;
}
public string Kunde { get; set; }
public string ProjektName { get; set; }
}
public class VolumeDetail
{
public VolumeDetail(int jahr, double[] volumen)
{
Jahr = jahr;
Volumen = volumen.ToList();
Summe = Volumen == null ? 0 : Summe = Volumen.Sum();
}
public int Jahr
{ get; private set; }
public List<double> Volumen
{ get; private set; }
public double Summe
{ get; private set; }
}
Random random = new Random();
var projektBezeichnungsTabelle = new List<JahresTabelle>();
var progStartJahr = 2022;
var progEndJahr = 2030;
//erstellt 50 Kunden mit einem Projekt
for (int tempID = 0; tempID < 50; tempID++)
{
var data = new JahresTabelle("Kunde" + tempID, "Projekt" + tempID);
for (int jahr = progStartJahr; jahr < progEndJahr; jahr++)
{
var volumesOfYear = new double[]
{
random.NextDouble(),
random.NextDouble(),
random.NextDouble(),
};
data.Add(new VolumeDetail(jahr, volumesOfYear));
}
projektBezeichnungsTabelle.Add(data);
}
//create columns
DataGridTextColumn column;
var columnCollection = new List<DataGridTextColumn>();
{
//kunde
column = new DataGridTextColumn()
{
Header = "Kunde",
Binding = new Binding("Kunde")
};
columnCollection.Add(column);
//projekt
column = new DataGridTextColumn()
{
Header = "ProjektName",
Binding = new Binding("ProjektName")
};
columnCollection.Add(column);
//dynamic year columns
for (int j = progStartJahr; j < progEndJahr; j++)
{
column = new DataGridTextColumn()
{
Header = "Vol. im Jahr " + j,
Binding = new Binding(string.Format("[{0}].Jahr.Summe", j - progStartJahr))
};
columnCollection.Add(column);
}
- Wer lesen kann, ist klar im Vorteil
- Meistens sitzt der Fehler vorm Monitor
- "Geht nicht" ist keine Fehlermeldung!
- "Ich kann programmieren" != "Ich habe den Code bei Google gefunden"
hat etwas gebraucht bis ich dazu gekommen bin den Vorschlag umzusetzen. Dabei habe ich erst gemerkt, warum jbrown das Aussehen nicht nachvollziehen konnte. Mein Programmcode ist massiv mit meiner Beschreibung kollidiert. Habe nun den Code etwas angepasst. Leider bekomme ich das Binding nicht hin. Könnt Ihr mir hier noch einmal auf die Sprünge helfen? Hier der neue Code:
public class JahresTabelle: ObservableCollection<VolumenDetails>
{
public JahresTabelle(String m_Kunde, String m_Projekt, String m_Vertriebler)
{
Kunde = m_Kunde;
Projekt = m_Projekt;
Vertriebler = m_Vertriebler;
}
public String Kunde { get; set; }
public String Projekt { get; set; }
public String Vertriebler { get; set; }
}
public class VolumenDetails
{
public VolumenDetails(int m_Jahr, double m_Volumen)
{
Jahr = m_Jahr;
Volumen = m_Volumen;
}
public Int32 Jahr { get; private set; }
public Double Volumen { get; private set; }
}
und hier der Code zum Erzeugen und (leider Nicht-)Befüllen der Spalten. Wie muss das Binding aussehen? Ach ja, habe die ColumnCollection durch das DataGrid selbst ersetzt. Sollte doch trotzdem gehen?
public List<JahresTabelle> ProjektUmsatzTabelle = new List<JahresTabelle>();
foreach (Projekt Pro in ZKUmsatzPro)
{
JahresTabelle JaTab = new JahresTabelle(Pro.Kundenname, Pro.Projektname, Pro.Vertriebler);
for (int j = ProgStartJahr; j < ProgEndJahr; j++)
{
Double Vol = Pro.QuartalsZahlen.Where(x => x.Jahr == j).Sum(x => x.EntwicklungsU + x.ProduktU);
JaTab.Add(new VolumenDetails(j, Vol));
}
ProjektUmsatzTabelle.Add(JaTab);
}
DataGridTextColumn Spalte;
{
Spalte = new DataGridTextColumn() { Header = "Kunde", Binding = new Binding("ProjektUmsatzTabelle.Kunde") };
Dgd_Umsatzvorschau.Columns.Add(Spalte);
Spalte = new DataGridTextColumn() { Header = "Projekt", Binding = new Binding("ProjektUmsatzTabelle.Projekt") };
Dgd_Umsatzvorschau.Columns.Add(Spalte);
Spalte = new DataGridTextColumn() { Header = "Vertriebler", Binding = new Binding("ProjektUmsatzTabelle.Vertriebler") };
Dgd_Umsatzvorschau.Columns.Add(Spalte);
for (int j = ProgStartJahr; j ≤ ProgEndJahr; j++)
{
Spalte = new DataGridTextColumn()
{
Header = j,
Binding = new Binding(string.Format("ProjektUmsatzTabelle.[{0}].Volumen", j - ProgStartJahr))
};
Dgd_Umsatzvorschau.Columns.Add(Spalte);
}
}
Viiiiiiiieeeelen Dank
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von NoSonOfMine am .
das Thema macht mich echt fertig. Hier sieht man den VB.net + Forms Hobbyprogrammierer, der sich jetzt in C# versucht. Komme mit der Bindung nicht klar. Habe kein MVVM gebastelt, sondern einfach nur ObservableCollections:
public ObservableCollection<JahresTabelle> ProjektUmsatzTabelle = new ObservableCollection<JahresTabelle>();
public class JahresTabelle: ObservableCollection<VolumenDetails>
{
public JahresTabelle(String m_Kunde, String m_Projekt, String m_Vertriebler)
{
Kunde = m_Kunde;
Projekt = m_Projekt;
Vertriebler = m_Vertriebler;
}
public String Kunde { get; set; }
public String Projekt { get; set; }
public String Vertriebler { get; set; }
}
public class VolumenDetails
{
public VolumenDetails(int m_Jahr, double m_Volumen)
{
Jahr = m_Jahr;
Volumen = m_Volumen;
}
public Int32 Jahr { get; private set; }
public Double Volumen { get; private set; }
}
foreach (Projekt Pro in ZKUmsatzPro)
{
Pro.QuartaleBerechnen();
JahresTabelle JaTab = new JahresTabelle(Pro.Kundenname, Pro.Projektname, Pro.Vertriebler);
for (int j = ProgStartJahr; j < ProgEndJahr; j++)
{
Double Vol = Pro.QuartalsZahlen.Where(x => x.Jahr == j).Sum(x => x.EntwicklungsU + x.ProduktU);
JaTab.Add(new VolumenDetails(j, Vol));
}
ProjektUmsatzTabelle.Add(JaTab);
var Spalte = new DataGridTextColumn() { Header = "Vertriebler",Binding = new Binding("Vertriebler") };
Dtg_Umsatzvorschau.Columns.Add(Spalte);
Ich sehe die Spaltenüberschriften und eine (nicht in Zusammenhang mit der Zeilenanzahl von ProjektUmsatzTabelle stehenden) Anzahl von Leerzeilen, allerdings ohne Inhalt. Könnt Ihr mir die korrekte Bindung im XAML und bei der Spalte nennen?
Was mir noch nicht gefällt, ist, dass im DataGrid nun 2x die Spalten stehen: die ersten Spalten (Kunde, Projekt, Vertriebler, [1 .. x]Jahre) sind programmtechnisch erzeugt.
Danach werden allerdings noch einmal die Spalten (Kunde, Projekt, Vertriebler, Collection) angehängt. Kann diese auch im ersten Durchgagn der Erzeugung durch RemoveAt() nicht löschen.
Zusätzlich: wie bekomme ich hier die Daten formatiert?
Spalte = new DataGridTextColumn()
{
Header = j,
Width = 80,
Binding = new Binding(string.Format("[{0}].Volumen", j - ProgStartJahr))
};
Ich möchte 1.000er Punkte setzen und alle Nachkommastellen abschneiden. Zusätzlich den Spalteninhalt rechtsbündig ausrichten. Wenn ich das richtig gelesen habe, muss das alles in die Binding -Zeile rein.
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von NoSonOfMine am .
Hallo und Danke für die tatkräftige Unterstützung.
<DataGrid AutoGenerateColumns="False" />
hat hier geholfen.
Habe mich während dem Einwühlen in die Programmierung an der ein- oder anderen Stelle gefragt was die Entwickler von Microsoft da geraucht haben oder was muss ich rauchen muss, um die Denkstruktur zu verstehen.
Da ich ja nicht alle Spalten rechtsbündig formatiert haben will, habe die Formatierung zwischenzeitlich so gelöst:
Style s = new Style();
s.Setters.Add(new Setter(TextBlock.TextAlignmentProperty, TextAlignment.Right));
for (int j = ProgStartJahr; j ≤ ProgEndJahr; j++)
{
Spalte = new DataGridTextColumn()
{
Header = j,
Width = 80,
Binding = new Binding(string.Format("[{0}].Volumen", j - ProgStartJahr)),
CellStyle = s
};
Dtg_Umsatzvorschau.Columns.Add(Spalte);
}
Wer kann denn auch erahnen, dass die Textausrichtung in Cellstyle.TextBlock versteckt ist?
Die Formatierung mit Punkten mache ich nun eben früher und übergebe schon fertig formatierte Strings in die DataGridTextColumns.
Warum in aller Welt möchtest du denn deine DataGrid-Spalten manuell erstellen???
In deinem DataModel hast du in der Klasse: JahresTabelle alle Eigenschaften, inclusive der JahresVolumen-Liste, definiert und brauchst nun diese nur noch an deine View binden. Für die einfachen Eigenschaften definierst du im XAML eine DataGridTextColumn (mit ein wenig Formatierung) und für die Liste, die du horizontal darstellen möchtest, bietet sich eine DataGridTemplateColumn mit einem DataTemplate das ein UniformGrid benutzt, an. Diese Lösung hat dir Wilfried bereits vorgeschlagen!
Mit 39 XAML-Zeilen für das gesamte DataGrid (incl. Formatierung) hast du dein gesamtes Problem erschlagen!
Am Anfang ist es etwas ungewohnt sich in MVVM einzuarbeiten, aber wenn du WPF nutzen möchtest, ist das der effektivste und rubusteste Weg Windows Anwendungen zu erstellen. (Zumal du quasi ja schon mit einem DataModel arbeitest.)
Ich habe für dein Problem mal eine kleine Aplikation geschrieben. Die längste Zeit habe ich für die Erstellung von sinnvollen Beispiel-Daten gebraucht!
Das DataGrid kannst du so 1:1 in deine Anwendung kopieren.
Jetzt brauchst du nur noch eine Klasse für das ViewModel zu erstellen und in dieser deine Liste der JahresTabellen (ProjektUmsatzTabelle) als öffentliche Eigeschaft zu instanzieren.
Fertig!
Damit die Zusammenhänge leichter nachvollzogen werden können, poste ich mal die komplette CodeBehind-Datei, in der ich das ViewModel und dein DataModel (welche bei größeren Projekten in seperate Dateien ausgelagert werden) befinden.
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows;
namespace WpfApp1
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
}
#region ViewModel
...
Hoppla ich kann hier nur 8000 Zeichen posten da muss ich die CodeBehind in eine andere Antwort packen ...
Die CodeBehind incl. View- und Data-Model. (Um exakt zu sein ... Mir ist bewusst, dass das DataModel kein echtes DataModel darstellt sondern nur zwei Klassen die eine Daten-Struktur modelieren.)
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows;
namespace WpfApp1
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
}
#region ViewModel
public class VMUmsatzuebersicht : INotifyPropertyChanged
{
public ObservableCollection<JahresTabelle> ProjektUmsatzTabelle { get; set; } // Liste der Daten deklarieren
#region Konstruktor
public VMUmsatzuebersicht()
{
ProjektUmsatzTabelle = GetZufallsDaten(); // Zufalls-Beispieldaten erzeugen
}
#endregion
#region Oberfläche aktualisieren (Achtung: Die akt. Klasse muss von der Schnittstelle: INotifyPropertyChanged abgeleitet sein!!!)
public event PropertyChangedEventHandler PropertyChanged;
protected void OnChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
#region Methoden des VM
private ObservableCollection<JahresTabelle> GetZufallsDaten(int anzahl = 50, int projekteProKunde = 5, int anzahlVertriebler = 7, int startJahr = 2022, int endJahr = 2030)
{
Random random = new Random();
ObservableCollection<JahresTabelle> projektBezeichnungsTabelle = new ObservableCollection<JahresTabelle> (); // Liste der Jahres-Tabellen initalisieren
int aktKunde = 0; // Akt. Kunde (Wechsel entsprechend Projekte/Kunde)
int aktProjekt = 0; // Akt. Projekt (Pro Kunde)
for (int n = 0; n < anzahl; n++) // (Zufalls) JahresTabellen in der gewünschten Anzahl erstellen
{
List<VolumenDetails> volDetails = new List<VolumenDetails>(); // Liste der Volumendetails initalisieren
double gesamtVolumen = 0; // Gesamtvolumen initalisieren
if (n % projekteProKunde == 0 || n == 0) // Kundenwechsel?
{
aktKunde++; // Kunde inkrementieren
aktProjekt = 0; // Projekt zurücksetzen
}
aktProjekt++; // Projekt inkrementieren
for (int jahr = startJahr; jahr < endJahr; jahr++) // (Zufalls) Jahres-Volumen im gewünschten Zeitraum erstellen
{
double jahresVolumen = random.NextDouble() * 10000; // (Zufalls) Jahres-Volumen erstellen
gesamtVolumen += jahresVolumen; // Gesamtvolumen aktualisieren
volDetails.Add(new VolumenDetails(jahr, jahresVolumen)); // Volumen-Details der Liste der Volumen-Details hinzufügen
}
JahresTabelle data = new JahresTabelle("Kunde" + aktKunde.ToString(), "Projekt" + aktProjekt.ToString(), "Vertriebler" + random.Next(1, anzahlVertriebler).ToString(), gesamtVolumen, volDetails);
projektBezeichnungsTabelle.Add(data);
}
return projektBezeichnungsTabelle;
}
#endregion
}
#endregion
#region "DataModel"
public class JahresTabelle
{
public string Kunde { get; set; }
public string Projekt { get; set; }
public string Vertriebler { get; set; }
public double GesamtVolumen { get; set; }
public List<VolumenDetails> JahresVolumen { get; set; }
public JahresTabelle(string kunde, string projekt, string vertriebler, double gesamtVolumen, List<VolumenDetails> jahresVolumen)
{
Kunde = kunde;
Projekt = projekt;
Vertriebler = vertriebler;
GesamtVolumen = gesamtVolumen;
JahresVolumen = jahresVolumen;
}
}
public class VolumenDetails
{
public int Jahr { get; private set; }
public double Volumen { get; private set; }
public VolumenDetails(int jahr, double volumen)
{
Jahr = jahr;
Volumen = volumen;
}
}
#endregion
}
Bei dieser einfachen Anwendung benötigst du die Implementierung der INotifyPropertyChanged-Schnittstelle noch nicht. Da es aber ständig zur Aktualisierung der Oberfläche bei Eigenschaftsänderungen benötigt wird, füge ich sie grundsätzlich hinzu.
super lieben Dank für den Support und Deine Lösung inklusive der Erklärung.
Hatte mich jetzt mehrere Tage nicht mehr um das Projekt gekümmert, da ich mit anderen Jahresendspurtthemen meiner eigentlichen beruflichen Tätigkeit mehr als gut eingespannt war.
Das Durchdringen und überarbeiten wird sicherlich ein Teil meines Weihnachtsurlaubs.
Melde mich sicher wieder bei Fragen.
Wünsche Euch allen schon mal eine ruhige und besinnliche Weihnacht.
Bedenke aber, daß der Code von perlfred die Jahresvolumen alle in einerDataGrid-Spalte darstellt, nicht wie bei deiner bisherigen Lösung in verschiedenen Spalten.
Zuerst einmal Th69 du hast natürlich Recht! Die Lösung geht auch inhaltlich etwas an der Aufgabenstellung der Überschrift des Diskussionsbeitrages vorbei, aber vielleicht benötigt der TS die Spalten ja nur optisch!? Und dann ist diese Lösung Aufwandsseitig wohl nicht mehr zu toppen. :-)
Aber es geht natürlich auch anders ... deshalb hier der zweite Lösungsansatz.
Bei diesem benutze ich Value-Converter um die Werte der JahresVolumen den einzelnen Spalten des DataGrid's zuzuordnen. Die Zuordnung wird über eine Nummer, die als Convert-Parameter angegeben wird, ausgeführt.
Die Wirkungsweise anhand eines ValueConverter: (Dieser ValueConverter "erzeugt" die Spalten-Überschriften anhand des Jahres des ersten Eintrages der Jahres-Tabelle.)
[System.Windows.Data.ValueConversion(typeof(ObservableCollection<JahresTabelle>), typeof(string))]
public class HeaderBezeichnung_Converter : System.Windows.Data.IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value != DependencyProperty.UnsetValue && value != null && value is ObservableCollection<JahresTabelle> jahresTabelle) // Value enthält gültige Werte
if (System.Convert.ToInt32(parameter) > -1)
{
int SpaltenNr = System.Convert.ToInt32(parameter); // Spalten-Nummer
if (jahresTabelle.Count > 0 && jahresTabelle[0].JahresVolumen.Count ≥ SpaltenNr) // Spalte vorhanden?
return jahresTabelle[0].JahresVolumen[SpaltenNr].Jahr.ToString(); // Jahr (des 1. Eintrages) als Spaltenüberschrift zurückgeben
}
return string.Empty; // Wenn keine gültigen Werte vorliegen, "Leere" Spaltenbezeichnung zurückgeben
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotSupportedException(); // Back-Funktion nicht implementiert
}
}
Nach dem validieren der JahresTabelle und des Parameter-Wertes prüfe ich, ob die JahresVolumen-Liste einen Eintrag in der Position besitzt, die ich als Parameter spezifiziert habe. Wenn ja gebe ich das Jahr zurück, ansonsten eine leere Bezeichnung.
Als Beispiel: Ich möchte in der DataGrid-Spalte das Jahr des 2. Umsatz-Eintrages, als Header-Text, darstellen:
Ich hole mir über den DataContext des Window (=ViewModel) die ProjektUmsatzTabelle und spezifiziere über den ConvertParameter den wievielten Eintrag der JahresVolumen-Liste ich ansprechen möchte.
Adäquate ValueConverter (Zuordnung der JahresVolumen-Einträge über die Parameter-Nummer) benutze ich für die Darstellung der Volumen-Werte und für die Steuerung der Sichtbarkeit der DataGrid-Spalten.
1. Die Steuerung der Sichtbarkeit der DataGrid-Spalten kann nicht über einen ValueConverter, der an die Visibility-Eigenschaft gebunden wird, ausgewertet werden, da ausgeblendete DataGrid-Spalten Binding-Fehler verursachen. Genau aus diesem Grund wurde die Sichbarkeit über einen ValueConverter der die Spaltenbreite steuert, gesteuert.
Bei diesem Detail gleich noch der Hinweis, dass standardmäßig die MinWidth-Eigenschaft einer DataGrid-Spalte mit dem Wert 20 Pixel vorbelegt ist, der überschrieben werden muss.
2. DataGrid-Spalten sind abstrakte Objekte die nicht in der logischen oder visuellen Struktur eines Fensters erscheinen. Man kann keine Bindings direkt an die Width-Eigenschaft der DG-Spalte binden! (Das Binding wird niemals getriggert / ausgelöst!) Deshalb habe ich (entsprechend diesem Beitrag) die Width-Eigenschaft der DataGrid-Spalte über eine X-Referenz an die ActualWidth-Eigenschaft des Dummy-Objektes gebunden.
Da ich der Zeichenbegrenzung dieses Forums wieder bedrohlich nahe komme, habe ich das kleine Beispiel-Projekt hier für dich zum Nachvollziehen abgelegt.
In dem Bild sieht man das DataGrid zur Laufzeit. In den Spalten 3 und 9 habe ich die ConvertParameter so eingestellt, dass diese ausgeblendet werden. In deiner Anwendung müsstest du nun so viele Spalten implementieren (und konfigurieren), wie maximal benötigt werden könnten. Wenn die JahresVolumen-Liste weniger Einträge enthält, werden sie über den Spalten-Breite-Konverter ausgeblendet.
Also falls du die Spalten wirklich einzeln brauchst ... aber bedenke, sortieren kannst du sie so auch noch nicht, da dafür wieder ein spezieller Comparer implementiert werden müsste!
Hinweis 2: In meinem verlinkten Beispiel-Projekt ist natürlich auch die Variante 1 (MainWindow) komplett enthalten.
Dieser Beitrag wurde 2 mal editiert, zum letzten Mal von perlfred am .
einfach cool, wieviel Zeit Ihr in die Lösung meines Problems investiert habt. Ohne Euch wäre ich sicher nicht zu einer funktionierenden Lösung gekommen.
Die Dummy-Spalten-Lösung habe ich konzeptionell verstanden und setze ich in einem anderen Kontext so schon um. Hatte nur nicht daran gedacht, dass es hier auch gehen könnte.
Wahrscheinlich bin ich noch von meinen ersten Programmierversuchen zu Zeiten eines Apple 2 mit Compiler-Pascal verseucht: Bevorzuge eine Lösung dann, wenn die Laufzeit bzw. der Anzahl der Codezeilen am geringsten ist. Und die scheint mir bei meiner manuellen Generierung der Spalten ideal. Werde die Lösung erst einmal so verwenden.