Laden...

Wie kann ich mit einem Converter eine Zelle anhand des Datums rot, gelb oder grün einfärben?

Erstellt von mantis religiosa vor 3 Jahren Letzter Beitrag vor 3 Jahren 553 Views
M
mantis religiosa Themenstarter:in
2 Beiträge seit 2020
vor 3 Jahren
Wie kann ich mit einem Converter eine Zelle anhand des Datums rot, gelb oder grün einfärben?

Hallo,

ich stehe gerade auf dem Schlauch und hoffe mir kann hier jemand helfen.

Ich habe ein DataGrid mit einer Spalte das Datumsformate (DateTime) enthält. Dies stellt das Ende der Garantiezeit dar. Ich möchte nun den Rahmen der Zelle entsprechend der Garantiezeit einfärben. Rot = Garantie ist abgelaufen, Gelb = Weniger als 60 Tage Restlaufzeit und Grün = Mehr als 60 Tage bis Garantieende.

Dazu habe ich einen Converter erstellt, der wie folgt aussieht:


   public class MyDate2ColorConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            if(value != DBNull.Value)
            {
                //Datum liegt mehr als 60 Tage in der Zukunft
                if (System.Convert.ToDateTime(value).Date > DateTime.Now.AddDays(+60))
                {
                    return "Grün";
                }
                //Datum wurde noch nicht erreicht, liegt aber weniger als 60 Tage in der Zukunft
                if (System.Convert.ToDateTime(value).Date >= DateTime.Now && System.Convert.ToDateTime(value).Date >= DateTime.Now.Date.AddDays(+60))
                {
                    return "Gelb";
                }
                //Das Datum liegt in der Vergangenheit
                if (System.Convert.ToDateTime(value) < DateTime.Now)
                {
                    return "Rot";
                }
            }
            return "";
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            return "";
        }
    }

Im XAML wird dieser wie folgt genutzt:


                            <DataGridTextColumn.CellStyle>
                                <Style TargetType="DataGridCell" BasedOn="{StaticResource MahApps.Styles.DataGridCell}">
                                    <Setter Property="HorizontalAlignment" Value="Stretch"/>
                                    <Setter Property="HorizontalContentAlignment" Value="Center"/>
                                    <Style.Triggers>
                                        <DataTrigger Binding="{Binding Garantie, Converter={StaticResource MyDate2ColorConverter}}" Value="Grün">
                                            <Setter Property="BorderBrush" Value="Green"/>
                                        </DataTrigger>
                                        <DataTrigger Binding="{Binding Garantie, Converter={StaticResource MyDate2ColorConverter}}" Value="Gelb">
                                            <Setter Property="BorderBrush" Value="Yellow"/>
                                        </DataTrigger>
                                        <DataTrigger Binding="{Binding Garantie, Converter={StaticResource MyDate2ColorConverter}}" Value="Rot">
                                            <Setter Property="BorderBrush" Value="Red"/>
                                        </DataTrigger>
                                    </Style.Triggers>
                                </Style>
                            </DataGridTextColumn.CellStyle>

Leider funktioniert es nicht. Nur der Teil der Rot zurück gibt funktioniert, die beiden If-Anweisungen die zu Grün oder Gelb führen würden, scheinen nie zuzutreffen (was nach den Datumswerten die ich eingetragen habe aber der Fall sein müsste). Irgendwie habe ich das Gefühl, das dass mit den .AddDays nicht hinhaut, aber wieso?

Kann mir da evtl. jemand helfen? Ich möchte anmerken, dass ich gerade erst anfange mich mit Programmieren anzufreunden, also bitte keine tieferen Kenntnisse voraussetzen.

Danke!

5.658 Beiträge seit 2006
vor 3 Jahren

Du kannst im Converter einen Breakpoint setzen und die dann im Debugger anschauen, was dort passiert: [Artikel] Debugger: Wie verwende ich den von Visual Studio?

Du mußt auch nicht bei jedem Vergleich den Wert wieder in ein Datum umwandeln. Das kann man am Anfang einmal machen. Bei "Gelb" scheinst du gemäß der Beschreibung "≥" anstatt "≥" zu verwenden.

Weeks of programming can save you hours of planning

2.079 Beiträge seit 2012
vor 3 Jahren

Ich möchte anmerken, dass ich gerade erst anfange mich mit Programmieren anzufreunden, also bitte keine tieferen Kenntnisse voraussetzen.

Dann ist WPF vielleicht nicht gerade der ideale Einstieg.
Einfacher wäre, wenn Du dich mit den C#-Grundlagen bei kleinen Konsolenanwendungen vertraut machst.

Abgesehen davon: Mindestens den Debugger solltest Du kennen:
[Artikel] Debugger: Wie verwende ich den von Visual Studio?
Heißt: Setz einen Breakpoint in den Converter und schau dir an, was er bei welchem Datum tut, denn scheinbar treffen die beiden ersten Bedingungen nie zu.

By the way:
Ein Converter bzw. das Binding von WPF kann alles mögliche entgegen nehmen.
Du solltest deiner Garantie-Property also den Typ DateTime geben (sofern möglich) und im Converter brauchst Du dann nur nach DateTime casten und sparst dir das ständige fehleranfällige "ToDateTime" - und überall sonst auch.

PS:
Zu langsam

PPS @MrSparkle:
Du wolltest "≤" anstatt "≥" schreiben?

NuGet Packages im Code auslesen
lock Alternative für async/await

Beim CleanCode zählen nicht die Regeln, sondern dass wir uns mit diesen Regeln befassen, selbst wenn wir sie nicht befolgen - hoffentlich nach reiflichen Überlegungen.

M
mantis religiosa Themenstarter:in
2 Beiträge seit 2020
vor 3 Jahren

Hallo zusammen,

vielen Dank für die Hilfe. Das mit den Breakpoints hat mich zur Lösung gebracht nachdem ich mir zuvor die Werte mit denen ich hantiere, in Variablen geschrieben habe.

Das sieht jetzt wie folgt aus:


        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            if(value != DBNull.Value)
            {
                DateTime dtValue = System.Convert.ToDateTime(value).Date;
                DateTime dtNowPlus60 = DateTime.Now.Date.AddDays(+60);
                DateTime dtToday = DateTime.Now.Date;
                //Datum liegt mehr als 60 Tage in der Zukunft
                if (dtValue > dtNowPlus60)
                {
                    return "Grün";
                }
                //Datum wurde noch nicht erreicht, liegt aber weniger als 60 Tage in der Zukunft
                if (dtValue >= dtToday && dtValue <= dtNowPlus60)
                {
                    return "Gelb";
                }
                //Das Datum liegt in der Vergangenheit
                if (dtValue < dtToday)
                {
                    return "Rot";
                }
            }
            return "";
        }

Bei Gelb hatte ich wirklich den Fehler statt ≤ ≥ geschrieben zu haben. So funktioniert nun alles. Ich frage mich nur, warum die erste if-Anweisung vorher nicht gezogen hat. Was ist der Unterschied es vorher in eine Variable zu schreiben als es direkt im Vergleich zu tun?

@Palladin007
Prizipiell gebe ich dir recht was das kleine Anfangen angeht. Allerdings halte ich es für einfacher, sich ein Anwendungsbeispiel/Ziel aus der Praxis zu suchen, da ist die Motivation doch deutlich höher wenn man das geschaffene direkt bei der täglichen Arbeit einsetzen kann 😃 Allerdings werde ich mich jetzt erstmal mit dem Debugging auseinander setzen, ihr habt da ja gute Infos!

2.079 Beiträge seit 2012
vor 3 Jahren

Du hast im alten Code "DateTime.Now" anstelle von "DateTime.Now.Date" verwendet.
Ohne groß drüber nachgedacht zu haben: Vielleicht liegt's daran?
By the way: Es gibt auch DateTime.Today

Allerdings halte ich es für einfacher, sich ein Anwendungsbeispiel/Ziel aus der Praxis zu suchen, da ist die Motivation doch deutlich höher wenn man das geschaffene direkt bei der täglichen Arbeit einsetzen kann

Das stimmt ich dir zu, allerdings bringt nicht jeder das dafür nötige Durchhaltevermögen. Ich will ja, dass die Leute am Ball bleiben, daher rate ich im Zweifelsfall lieber zum einfacheren Einstieg.
Wenn Du da anders bist, dann mach weiter mit WPF, aber rechne damit, dass Du vermutlich viele konzeptionell grundlegende Fehler machst, die sich nicht "mal eben so" beheben lassen 😉

NuGet Packages im Code auslesen
lock Alternative für async/await

Beim CleanCode zählen nicht die Regeln, sondern dass wir uns mit diesen Regeln befassen, selbst wenn wir sie nicht befolgen - hoffentlich nach reiflichen Überlegungen.

C
2.121 Beiträge seit 2010
vor 3 Jahren

Ich frage mich nur, warum die erste if-Anweisung vorher nicht gezogen hat.

Schau dir das auch im Debugger an. Ich sehe auf Anhieb keinen Fehler dabei.

Was ist der Unterschied es vorher in eine Variable zu schreiben als es direkt im Vergleich zu tun?

Schon die Lesbarkeit ist um einiges besser wenn du keinen irre langen Ausdruck schreibst, sondern eine passend benannte Variable.
Wenn du das dt weglässt und die Variablen date und today nennst, wirds noch flüssiger lesbar.

Außerdem kannst du ein paar Vergleiche weglassen.
Wenn das erste if "dtValue > dtNowPlus60" nicht zutrifft, ist klar dass "dtValue ≤ dtNowPlus60" ist.
Damit reduziert sich das ganze dann zu


if (date > today+60)
  return grün

else if (date >= today)
  return gelb

else
  return rot

(mit oder ohne else, wie du es schöner findest)

Anstatt System.Convert würde ich value direkt casten "(DateTime)value". Sieht auch direkt wieder kürzer aus und wenn value kein DateTime ist, knallt dir dein Programm komplett weg, anstatt mit einem eventuell falschen Wert unbemerkt falsch weiter zu machen.

2.079 Beiträge seit 2012
vor 3 Jahren

Bei der Gelegenheit würde ich auch direkt hinterfragen:

Warum der Check auf DBNull?

Wie ich es auch drehe und wende, mir fällt kein Fall ein, bei dem DBNull in der UI kein grober Design-Fehler ist 😉
Anstatt mit DBNull solltest Du direkt mit null arbeiten, das DBNull hat nur beim Zugriff auf die Datenbank seine Daseinsberechtigung.
Normalerweise geht man dann beim Lesen aus der Datenbank hin, prüft auf DBNull und "liest" das dann als null. Und damit der Wert null erlaubt (tut DateTime normalerweise nicht), schreib "DateTime?", dann wird ein Nullable-DateTime daraus.

NuGet Packages im Code auslesen
lock Alternative für async/await

Beim CleanCode zählen nicht die Regeln, sondern dass wir uns mit diesen Regeln befassen, selbst wenn wir sie nicht befolgen - hoffentlich nach reiflichen Überlegungen.

16.835 Beiträge seit 2008
vor 3 Jahren

Basics zu Datenbanken: niemals mit DateTime arbeiten, sondern immer mit DateTimeOffset.
Und DateTime.Now sowieso nicht, sondern wenn schon falsch, dann weniger schlimm falsch mit DateTime.UtcNow.