Nützliche Converter Sammlung – Teil 3

Durch das System von Data Binding kann man ganz einfach seine Properties aus den ViewModels an die View binden. Manchmal liegen die Daten aber nicht im gewünschten Format vor und daher kann man ganz einfach Converter schreiben, welche die Daten von Typ A in Typ B umwandelt. Dies ist nun der erste Teil, wo ich ein paar einfache Converter teilen möchte, welche meist in allen meinen App-Projekten zu finden sind. Die Syntax ist hierbei für Xamarin.Forms Apps, sollte aber leicht für UWP oder auch WPF angepasst werden können. In diesem Artikel nun ein paar weitere nützliche Converter.

Jeder Converter muss das Interface IValueConverter implementieren und damit die Methoden Convert und ConvertBack. In den meisten Fällen möchte man die Daten aus dem ViewModel für die View anpassen und daher reicht es aus nur die Convert-Methode zu implementieren.

Beginnen möchte ich diesen Teil der Artikel-Serie mit einem StringToHtmlWebViewSourceConverter. Möchte man HTML in seiner Xamarin.Forms App verwenden, so bietet sich die WebView als Control an. Diese erwartet entweder eine URL oder aber man kann auch lokalen HTML Content anzeigen lassen, in dem man den HTML-String in eine HtmlWebViewSource überführt, was die Aufgabe des vorliegenden Converters ist.

public class StringToHtmlWebViewSourceConverter : IValueConverter
{
    public object Convert(object value, Type targetType,
        object parameter, CultureInfo culture)
    {
        if (value is string htmlContent)
        {
            // maybe manipulate the htmlContent here
            return new HtmlWebViewSource { Html = htmlContent };
        }

        return null;
    }

    public object ConvertBack(object value, Type targetType,
        object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

Manchmal möchte man eine Zeitangabe nicht absolut, sondern relativ zur aktuellen Zeit angegeben. Für diesen Fall gibt es den DateTimeToRelativeDateTimeStringConverter. Ausgehend von einem übergebenen Datum wird dies relativ zur aktuellen Uhrzeit als String ausgegeben. Damit „spricht“ der Converter aktuell nur Deutsch, könnte aber mit wenig Aufwand auch mehrsprachig umgesetzt werden.

public class DateTimeToRelativeDateTimeStringConverter : IValueConverter
{
    public object Convert(object value, Type targetType,
        object parameter, CultureInfo language)
        {
            if (value is DateTime dateTimeValue)
            {
                return GetRelativeDate(dateTimeValue);
            }


            if (value is string stringValue)
            {
                var date = DateTime.Parse(stringValue);
                return GetRelativeDate(date);
            }

            if (value is long longValue)
            {
                var date = DateTimeOffset.FromUnixTimeSeconds(longValue).LocalDateTime;
                return GetRelativeDate(date);
            }

            return null;
        }

    public object ConvertBack(object value, Type targetType,
        object parameter, CultureInfo language)
        {
            return value;
        }

    static string GetRelativeDate(DateTime dateTime)
    {
        var timespan = DateTime.Now.Subtract(dateTime);
        var dayDiff = (int)timespan.TotalDays;
        int secDiff = (int)timespan.TotalSeconds;

        if (dayDiff < 0 || dayDiff >= 31)
            return string.Format("am {0:dd.MM.yyyy}", dateTime);

        if (dayDiff == 0)
        {
            if (secDiff < 60)
                return "gerade eben";

            if (secDiff < 120)
                return "vor 1 Minute";

            if (secDiff < 3600)
                return $"vor {Math.Floor((double)secDiff / 60)} Minuten";

            if (secDiff < 7200)
                return "vor 1 Stunde";

            if (secDiff < 86400)
                return $"vor {Math.Floor((double)secDiff / 3600)} Stunden";
        }

        if (dayDiff == 1)
            return "gestern";

        if (dayDiff < 7)
            return $"vor {dayDiff} Tagen";

        if (dayDiff < 31)
        {
            var weeks = Math.Ceiling((double)dayDiff / 7);
            if (weeks == 1)
                return "vor 1 Woche";

            return $"vor {weeks} Wochen";
        }

        return string.Format("am {0:dd.MM.yyyy}", dateTime);
    }
}

Im letzten Teil der Serie habe ich ja bereits den BoolToColorConverter vorgestellt. Diesen wollen wir jetzt erweitern, so dass er nicht nur Farben, sondern beliebige Objekte zurückgeben kann. Dies hat den Vorteil, dass der BoolToObjectConverter in nahezu allen Lebenslagen verwendet werden kann, wenn man zwischen zwei Optionen wählen kann, z.B. ob ein Text fett oder kursiv dargestellt werden soll.

public class BoolToObjectConverter : IValueConverter
{
    public object TrueValue { get; set; }
    public object FalseValue { get; set; }

    public object Convert(object value, Type targetType, 
        object parameter, CultureInfo culture)
    {
        if (value is bool boolValue)
            return boolValue ? TrueValue : FalseValue;

        return Color.Transparent;
    }

    public object ConvertBack(object value, Type targetType, 
        object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

Um den Converter nun zu verwenden, verwendet man das folgende Snippet.

<BoolToObjectConverter x:Key="BoolToObjectConverter" 
                       FalseValue="<Your Value #1>" 
                       TrueValue="<Your Value #2>" />

Dies ist der dritte Teil meiner kleinen Converter-Sammlung. Aber keine Angst ich habe noch zahlreiche weitere nützliche Converter zur Hand und werde in regelmäßigen Abständen immer mal wieder ein paar davon in meinem Blog vorstellen. Solltet ihr aber auch noch weitere Converter in fast allen euren Projekten verwenden, könnt ihr mir diese gerne in die Kommentare schreiben.

Xamarin.Forms Controls: RepeaterView WordPress-Seite als Xamarin.Forms App – Teil 4 DataTemplateSelector: Verschiedene DataTemplates für eine Liste