Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 | Suche | FAQ

Hauptmenü
myCSharp.de
» Startseite
» Forum
» Suche
» Regeln
» Wie poste ich richtig?

Mitglieder
» Liste / Suche
» Wer ist online?

Ressourcen
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Microsoft Docs

Team
» Kontakt
» Cookies
» Spenden
» Datenschutz
» Impressum

  • »
  • Community
  • |
  • Diskussionsforum
DataGrid an eine List mit variabler Spaltenzahl binden
NoSonOfMine
myCSharp.de - Member



Dabei seit:
Beiträge: 12

Themenstarter:

DataGrid an eine List mit variabler Spaltenzahl binden

beantworten | zitieren | melden

Hallo Forum,

habe eine Klasse mit folgenden Properties:


    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?

Danke und Gruß
private Nachricht | Beiträge des Benutzers
Th69
myCSharp.de - Experte

Avatar #avatar-2578.jpg


Dabei seit:
Beiträge: 4.487

beantworten | zitieren | melden

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 .
private Nachricht | Beiträge des Benutzers
jbrown
myCSharp.de - Member



Dabei seit:
Beiträge: 16

beantworten | zitieren | melden

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...
private Nachricht | Beiträge des Benutzers
NoSonOfMine
myCSharp.de - Member



Dabei seit:
Beiträge: 12

Themenstarter:

beantworten | zitieren | melden

Hallo jbrown,

so wie im 1. Teil Deines Posts:

Spalte Kunde | Spalte Projekt | Volumen[0] | Volumen[1] | Volumen[2] | Volumen[...]

Hoffe so habe ich es verständlicher ausgedrückt.

Gruß und Danke
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von NoSonOfMine am .
private Nachricht | Beiträge des Benutzers
Th69
myCSharp.de - Experte

Avatar #avatar-2578.jpg


Dabei seit:
Beiträge: 4.487

beantworten | zitieren | melden

Genauso habe ich es bei meinem Beitrag verstanden.
private Nachricht | Beiträge des Benutzers
NoSonOfMine
myCSharp.de - Member



Dabei seit:
Beiträge: 12

Themenstarter:

beantworten | zitieren | melden

Leider bin ich zu doof es umzusetzen. Probiere noch rum...
private Nachricht | Beiträge des Benutzers
NoSonOfMine
myCSharp.de - Member



Dabei seit:
Beiträge: 12

Themenstarter:

beantworten | zitieren | melden

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...

Binden:


            Dgd_Umsatzvorschau.ItemsSource = ProjektBezeichnungsTabelle;


           ProjektBezeichnungsTabelle.Clear();

            foreach (Projekt Pro in ZKUmsatzPro)
            {
                JahresTabelle Tab = new JahresTabelle();
                Tab.Kunde = Pro.Kundenname;
                Tab.Projekt = Pro.Projektname;

                List<Double> Vol = new List<double>();
                for (int j = ProgStartJahr; j ≤ ProgEndJahr; j++)
                {
                    Vol.Add(...Abfrage...);
                }
                Tab.Volumen = Vol;
                ProjektBezeichnungsTabelle.Add(Tab);

            }

            for (int j = ProgStartJahr; j ≤ ProgEndJahr; j++)
            {
                DataGridTextColumn Spalte = new DataGridTextColumn();
                Spalte.Header = j.ToString();
                Binding SpalteBinding = new Binding(string.Format("ProjektBezeichnungsTabelle.Volumen[{0}]", j - ProgStartJahr));
                Spalte.Binding = SpalteBinding;
                Dgd_Umsatzvorschau.Columns.Add(Spalte);
            }
private Nachricht | Beiträge des Benutzers
jbrown
myCSharp.de - Member



Dabei seit:
Beiträge: 16

beantworten | zitieren | melden

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);
                }
Attachments
private Nachricht | Beiträge des Benutzers
Th69
myCSharp.de - Experte

Avatar #avatar-2578.jpg


Dabei seit:
Beiträge: 4.487

beantworten | zitieren | melden

@NoSonOfMine: Laß ProjektBezeichnungsTabelle. weg beim Binding:


Binding SpalteBinding = new Binding(string.Format("Volumen[{0}]", j - ProgStartJahr));
Und vor dem Anfügen mußt du dann die Spalten neu erstellen (also so wie im Code von jbrown).

PS:
@jbrown: "[{0}].Jahr.Summe" ergibt so aber auch keinen Sinn (also wenn dann nur jeweils eine der drei Eigenschaften).
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von Th69 am .
private Nachricht | Beiträge des Benutzers
Wilfried
myCSharp.de - Member

Avatar #2TnJ7IKlYXgOor5sZSIA.jpg


Dabei seit:
Beiträge: 159
Herkunft: Radeberg

beantworten | zitieren | melden

Also ich würde ja MVVM einsetzen. Und anstelle Datagrid ein Listview.


        public ObservableCollection<JahresTabelle> Tabelle { get; set; }


        <ListView ItemsSource="{Binding Tabelle}" >
            <ListView.View>
                <GridView>
                    <GridViewColumn Header="Kunde" DisplayMemberBinding="{Binding Kunde}"/>
                    <GridViewColumn Header="Projekt" DisplayMemberBinding="{Binding Projekt}"/>
                    <GridViewColumn Header="Volumen">
                        <GridViewColumn.CellTemplate>
                            <DataTemplate>
                                <ItemsControl ItemsSource="{Binding Volumen}">
                                    <ItemsControl.ItemsPanel>
                                        <ItemsPanelTemplate>
                                            <UniformGrid Rows="1"/>
                                        </ItemsPanelTemplate>
                                    </ItemsControl.ItemsPanel>
                                    <ItemsControl.ItemTemplate>
                                        <DataTemplate>
                                            <TextBlock Text="{Binding}" Margin="0,0,3,0"/>
                                        </DataTemplate>
                                    </ItemsControl.ItemTemplate>
                                </ItemsControl>
                            </DataTemplate>
                        </GridViewColumn.CellTemplate>
                    </GridViewColumn>
                </GridView>
            </ListView.View>
        </ListView>

Und dann noch etwas schön machen.
- 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"

GidF
private Nachricht | Beiträge des Benutzers
NoSonOfMine
myCSharp.de - Member



Dabei seit:
Beiträge: 12

Themenstarter:

beantworten | zitieren | melden

Hallo zusammen,

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 .
private Nachricht | Beiträge des Benutzers
jbrown
myCSharp.de - Member



Dabei seit:
Beiträge: 16

beantworten | zitieren | melden


<DataGrid ItemsSource="{Binding Path=TestViewModel.ProjektUmsatzTabelle}"/>

Du bindest damit bereits an die Auflistung deines Typs "Jahrestabelle".
Analog zu Th69´s Vorgehen sollte es dann so in etwa gehen:


...
Spalte = new DataGridTextColumn() { Header = "Kunde", Binding = new Binding("Kunde") };
Spalte = new DataGridTextColumn() { Header = "Projekt", Binding = new Binding("Projekt") };
...
for (int j = ProgStartJahr; j ≤ ProgEndJahr; j++)
    {
        Spalte = new DataGridTextColumn()
        {
            Header = j,
            Binding = new Binding(string.Format("[{0}].Volumen", j - ProgStartJahr))
        };
        Dgd_Umsatzvorschau.Columns.Add(Spalte);
    }
Gestern, private Nachricht | Beiträge des Benutzers
NoSonOfMine
myCSharp.de - Member



Dabei seit:
Beiträge: 12

Themenstarter:

beantworten | zitieren | melden

Hallo,

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; }
    }

im XAML Dokument habe ich folgende Bindung:

                                <DataGrid Name="Dtg_Umsatzvorschau" IsReadOnly="True" ItemsSource="{Binding Source=ProjektUmsatzTabelle}"/>

und die Spalten versuche ich so zu befüllen:


            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?
Gestern, private Nachricht | Beiträge des Benutzers
NoSonOfMine
myCSharp.de - Member



Dabei seit:
Beiträge: 12

Themenstarter:

beantworten | zitieren | melden

Habe eine Lösung gefunden. Habe anstatt im XAML den Programmcode ergänzt mit:


            Dtg_Umsatzvorschau.ItemsSource = ProjektUmsatzTabelle;

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 Gestern, .
Gestern, private Nachricht | Beiträge des Benutzers
jbrown
myCSharp.de - Member



Dabei seit:
Beiträge: 16

beantworten | zitieren | melden

Nicht einfach aufgeben

Die DataGrid Eigenschaft AutoGenerateColumns sollte das erste Problem lösen.


<DataGrid AutoGenerateColumns="False" ItemsSource="{Binding ProjektUmsatzTabelle}"/>

Diese kannst du natürlich auch so setzen:


Dtg_Umsatzvorschau.AutoGenerateColumns=false;
Dtg_Umsatzvorschau.ItemsSource = ProjektUmsatzTabelle;


Formatierung:
Standard numeric format strings

Wenn du das erledigt hast, ist dies eine Variante für das nächste Problem:

<DataGrid.ColumnHeaderStyle>
    <Style TargetType="{x:Type DataGridColumnHeader}">
        <Setter Property="FontWeight"  Value="Bold" />
        <Setter Property="HorizontalAlignment" Value="Center" />
        <Setter Property="HorizontalContentAlignment" Value="Center" />
    </Style>
</DataGrid.ColumnHeaderStyle>

Du solltest neben all dem aber versuchen zu verstehen, warum deine Bindung in XAML nicht klappt, die im Codebehind jedoch schon.
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von jbrown am Heute, .
Heute, private Nachricht | Beiträge des Benutzers
NoSonOfMine
myCSharp.de - Member



Dabei seit:
Beiträge: 12

Themenstarter:

beantworten | zitieren | melden

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.
Heute, private Nachricht | Beiträge des Benutzers