C# mit WPF XAML / Zelle in einem DataGrid ermitteln und Hintergrundfarbe ändern

guenter024

Erfahrenes Mitglied
Hallo,
habe folgende Schleife, mit der ich die Daten eines DataGrid durchlaufe
C#:
foreach (var item in MeinDataGrid.Items.OfType<Daten>())
{
    string Ergebnis = item.Ergebnis;
    int checkErgebnis = Convert.ToInt32(Ergebnis);
   
    if (checkErgebnis <= 0)
    {
         var row = item.Index;
        Console.WriteLine(row + " : " + Ergebnis);
    }
}

In der Spalte "Ergebnis" stehen numerische Werte, die positiv oder negativ sein können.
Wenn der Wert, den ich dann mit checkErgebnis prüfen möchte, kleiner gleich 0 ist, dann soll in dieser Zelle die Hintergrundfarbe geändert werden.
Nur wie stelle ich das an?
Ich finde nirgendwo ein Beispiel dazu, wie ich die Zelle ansprechen kann.

Hoffe jemand kann mir helfen.

Liebe Grüße


Edit: Console.WriteLine(row + " : " + Ergebnis); diente einfach nur als Kontrolle und gibt mir schön die Zeilennummer und den Wert aus. Soweit funktioniert es praktisch schon :)
 

Turri

Erfahrenes Mitglied
Hallo,

wie schaut denn dein Xaml-Code aus?

Ich nehme mal an, im ViewModel hast du eine List (oder ähnliches) vom Typ "Daten" welches du via "Itemsource Binding" direkt an das Datagrid hängst.

Meine Idee wäre, dass du in der "Daten"-Klasse ein Boolsches Getter Property erstellst und nennst es "IsPositive" oder sowas.

Danach könntest du im XAML-Code mit einem DataTrigger arbeiten, damit der Xaml-Code die Farbänderung für dich macht.

z.b. so:
Code:
<DataGrid>
....
<DataGrid.CellStyle>
    <Style TargetType="DataGridCell" BasedOn="{StaticResource DefaultDataGridCellStyle}">
        <Style.Triggers>
            <DataTrigger Binding="{Binding IsPositive, UpdateSourceTrigger=PropertyChanged}" Value="True">
                <Setter Property="Foreground" Value="Green"/>
            </DataTrigger>
            <DataTrigger Binding="{Binding IsPositive, UpdateSourceTrigger=PropertyChanged}" Value="False">
                <Setter Property="Foreground" Value="Red"/>
            </DataTrigger>
         </Style.Triggers>
     </Style>
</DataGrid.CellStyle>

Code ist ungetestet.
 

guenter024

Erfahrenes Mitglied
Hallo,
vielen Dank für deine Antwort.
Habe mittlerweile schon weiter getestet.
Aktuell habe ich im Code nur einen RowStyle.
XML:
<DataGrid x:Name="MeinDataGrid" VerticalAlignment="Stretch" IsReadOnly="True" AlternatingRowBackground="#EFEFEF">
                <DataGrid.RowStyle>
                    <Style TargetType="DataGridRow">
                        <Style.Triggers>
                            <DataTrigger Binding="{Binding Path=Color}" Value="1">
                                <Setter Property="Background" Value="#FFF59494" />
                                <Setter Property="Foreground" Value="White" />
                            </DataTrigger>
                        </Style.Triggers>
                    </Style>
                </DataGrid.RowStyle>
                <DataGrid.Columns>
<!-- ... hier stehen die Columns ... -->
Das ändern der Hintergrundfarbe habe ich dann so versucht:
C#:
foreach (var item in MeinDataGrid.Items.OfType<Daten>())
{
    string Ergebnis = item.Ergebnis;
    int checkErgebnis = Convert.ToInt32(Ergebnis);
 
    if (checkErgebnis <= 0)
    {
        item.Color = 1;
    }
}
Die Zeilen werden auch schon markiert
Aber irgendwie funktioniert es so nicht ganz richtig.
Manchmal wird die Hintergrundfarbe nicht geändert und nach dem Scrollen verschiebt es sich irgendwie...

Hast du eventuell ein Beispiel für den C#-Code mit der Property?


Wenn ich dein XAML Beispiel einfüge, wie muss ich dann die StaticResource definieren?
Ich möchte ja sonst, dass die Zeilenhintergrundfarbe sich abwechselt.
XML:
    <Window.Resources>
        <Style x:Key="DefaultDataGridCellStyle" TargetType="DataGridCell">
            <Setter Property="Background" Value="White" />
            <Setter Property="Foreground" Value="Black" />
        </Style>
    </Window.Resources>
dann ist der Hintergrund immer weiß...

Sorry, C# mit XAML ist noch neu für mich, bin sonst "PHP-ler" ;)

EDIT: Habe eben gemerkt, dass AlternatingRowBackground="#EFEFEF" das Problem der Zeilenverschiebung auslöst. Habe das mal probehalber entfernt, die Zeilen würden jetzt schon mal richtig markiert. Ich möchte aber nicht die ganze Zeile, sondern nur den CellStyle ändern.
Also weitere Hilfe würde mich sehr freuen :)
 
Zuletzt bearbeitet:

Turri

Erfahrenes Mitglied
Ich möchte aber nicht die ganze Zeile, sondern nur den CellStyle ändern.
Naja wie schon beschrieben, müsstest du den CellStyle ändern und nicht den RowStyle.

Das "BasedOn={StaticResource...}" kannst du auch erstmal einfach weglassen...
Das ist ja "nur" ein Default Style den ich für dieses DataGrid verändert hatte.
 

guenter024

Erfahrenes Mitglied
Hallo,

Naja wie schon beschrieben, müsstest du den CellStyle ändern und nicht den RowStyle.

;) genau das will ich ja, aber wie?

Wie müsste ich meine Schleife denn ändern?

Sagen wir ich binde diesen CellStyle ein:
XML:
                <DataGrid.CellStyle>
                    <Style TargetType="DataGridCell">
                        <Style.Triggers>
                            <DataTrigger Binding="{Binding Color}" Value="1">
                                <Setter Property="Foreground" Value="Red"/>
                            </DataTrigger>
                        </Style.Triggers>
                    </Style>
                </DataGrid.CellStyle>

Wie kann ich dann in meiner C#-for-Schleife genau diese Zelle anprechen, welche checkErgebnis <= 0 ist?
Das kann doch nicht so schwer sein, ich stehe hier einfach auf dem Schlauch.

In PHP würde ich halt einfach im HTML eine class oder ein Style-Attribut mit der Farbe vergeben und diese dann in PHP Zeilenweise reinschreiben oder eben nicht. Wie mache ich das in C#??

Edit:
Ich schreibe es einfach mal so wie ich es mir denke, wie es sein sollte:
PHP:
foreach (var item in MeinDataGrid.Items.OfType<Daten>())
{
    string Ergebnis = item.Ergebnis;
    int checkErgebnis = Convert.ToInt32(Ergebnis);
 
    if (checkErgebnis <= 0)
    {
        item.SPALTE.Color= 1;
    }
}

Wie definiere ich hier die Zelle bzw. die Spalte in dieser Reihe??
 
Zuletzt bearbeitet:

Turri

Erfahrenes Mitglied
Hallo,

es ist für mich immer noch ein raten, wie dein Code aussieht.
Zeig mal bitte deine "Daten"-Klasse
und den Xaml-Code vom kompletten Datagrid (das Binding interessiert mich hier).

Ich vermute die Datenklasse sieht irgendwie so aus:
Code:
public class Daten
{
    public int Ergebnis { get; set; }  // zumindest ähnlich
....
}

1) Wenn du mit dem "IsPositive" Property arbeiten würdest.
Das in die "Daten-Klasse" rein.
Code:
public bool IsPositive
{
    get { return (this.Ergebnis > 0); }
}

Hab eben auch nochmal nachgeschaut, man kann den Style auch für eine bestimmte Spalte setzen.
Und nicht generell für alle Zellen via DataGrid.CellStyle.
z.b.
Code:
<DataGridTextColumn Binding="{Binding Ergebnis}">  // deine ColumnDefinition
    <DataGridTextColumn.ElementStyle>  // den Style nur für diese Spalte setzen
        <Style TargetType="{x:Type TextBlock}">
            <Style.Triggers>
                <Trigger Property="IsPositive" Value="True">
                    <Setter Property="Foreground" Value="Green"/>
                </Trigger>
                <Trigger Property="IsPositive" Value="False">
                    <Setter Property="Foreground" Value="Red"/>
                </Trigger>
           </Style.Triggers>
        </Style>
    </DataGridTextColumn.ElementStyle>
</DataGridTextColumn>
Deine Schleife im Code-Behind kannst du damit weglassen.

2) Wenn du aber unbedingt deine Schleife im Code-Behind durchlaufen willst, dann geht es vielleicht so.
Ohne Xaml-Änderung sondern direkt im Code-Behind...
Code:
foreach (DataGridViewRow row in MeinDataGrid.Rows)  // statt Items, durch die "Rows" gehen.
{
    // je nach dem in welcher Spalte du was ändern möchtest Index 0 = erste Spalte
    int erg = Convert.ToInt32(row.Cells[0...10...].Value); // in Value müsste das "Ergebnis" stehen
    if (erg < 0)
       row.Cells[0...10...].Style.Foreground=... red
    else
       row.Cells[0...10...].Style.Foreground=... green
}
Ob das hier eine elegante Variante ist, naja.

Ist weiterhin nicht getestet, hab gerade keinen Compiler parat. :)
 

guenter024

Erfahrenes Mitglied
Hallo,
danke für deine Hilfe :)
Den "Code-Behind" muss ich freilich nicht unbedingt, wenn es auch rein mit XAML geht umso besser.
Ich wusste ja nicht, das sowas möglich ist, wie gesagt, bin Neuling in XAML.

Nichtsdestotrotz habe ich nochmal eine Frage zur Schleife, weil du schreibst "DataGridViewRow row in MeinDataGrid.Rows" -> das ist aber soweit ich bisher weiß in WPF nicht mehr drin (Siehe Thread-Titel C# mit WPF XAML)


Mein Code ist total einfach, im Prinzip genau so wie du geschrieben hast, nur, dass "Ergebnis" in Daten ein String ist:
C#:
public class Daten
{
    public string Ergebnis { get; set; }
}
Somit habe ich die Property-Class so gesetzt:
C#:
public bool IsPositive()
{
    return (Convert.ToInt32(this.Ergebnis) > 0);
}

So schaut jetzt der DataGridTextColumn aus:
XML:
<DataGridTextColumn x:Name="Ergebnis" Binding="{Binding Ergebnis}" Header="Ergebnis" Width="1*" CanUserSort="False">
    <DataGridTextColumn.ElementStyle>
        <Style TargetType="{x:Type TextBlock}">
            <Style.Triggers>
                <Trigger Property="IsPositive"  Value="True">
                    <Setter Property="Foreground" Value="Green"/>
                </Trigger>
                <Trigger Property="IsPositive" Value="False">
                    <Setter Property="Foreground" Value="Red"/>
                </Trigger>
            </Style.Triggers>
        </Style>
    </DataGridTextColumn.ElementStyle>
</DataGridTextColumn>

Problem ist nun, er nimmt mir die Property="IsPositive" nicht an:
"Das Element "IsPositive" wurde nicht erkannt oder es kann nicht darauf zugegriffen werden.

Weißt du da nochmal Rat?
Nochmals danke :)
 

Turri

Erfahrenes Mitglied
Somit habe ich die Property-Class so gesetzt:
C#:
public bool IsPositive()
{
return (Convert.ToInt32(this.Ergebnis) > 0);
}
Du hast aus meinem Property eine Funktion gemacht, dann klappt das nicht mehr.
Mein Code war da schon richtig, nur das der "Convert" gefehlt hat.

Probiers mal so:
Code:
public bool IsPositive
{
    get { return (Convert.ToInt32(this.Ergebnis) > 0); }
}
 

guenter024

Erfahrenes Mitglied
Hallo,
nochmal danke, aber leider funktioniert dein Beispiel nicht.
Die Funktion habe ich , weil ich den Korrekturvorschlag von VS übernommen hatte.
Wenn ich es wieder ändere in deinen Property kommt auch wieder die Fehlermeldung.

Fehlermeldung:
"Das Element "IsPositive" wurde nicht erkannt oder es kann nicht darauf zugegriffen werden.

Geht es doch nur über Code-Behind?
Wenn ich im Trigger das Attribut "Property" einfüge macht mir VS ja vorschläge. Kann ich da womöglich gar keine eigenen Properties eintragen?

Irgendwo muss es doch da eine Lösung geben...

Oder bin ich hier im falschen Thread???? Wie gesagt, ich habe ja nicht Windows Forms-> siehe meine Überschrift. Ich habe WPF!
Kann das wer verschieben?


Edit: Beim Ausführen des Programms kommt auch die Fehlermeldung "Style Property "IsPositive" wurde in Typ "System.Windows.Controls.TextBlock" nicht gefunden."
 
Zuletzt bearbeitet:

Turri

Erfahrenes Mitglied
Hallo,

WPF ist schon klar, daher ist deine Frage hier falsch einsortiert.
@Moderator: Bitte nach WPF rüberschieben.

Dennoch war mir WPF klar.
Ich überlege nur gerade selbst woran es liegen kann.
Könnte am Kontext liegen in dem die DataGridColumn läuft.