简体   繁体   中英

Converter and enum to change Foreground color of TextBlock

I would like to display in a TextBlock my variable TrainDelay in a specific format

I used a Converter IntToTimeSpanConverter to format TrainDelay : (mm:ss)

so according to the value of TrainDelay such as:

  • Display Delayed (00:23) in red color
  • Display On Time (00:00) in dark color
  • Display In Advance (- 00:15) in green color

Some code:

public class TimeSpanFormatConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        int.TryParse(value.ToString(), out int time);
        value = TimeSpan.FromSeconds(time);
        if (string.IsNullOrWhiteSpace(value.ToString()) || ((TimeSpan)value).Equals(TimeSpan.MinValue))
            return "––:––";
        else if(time > 0)
        {
            return TrainDelay.Delayed + "  " + ((((TimeSpan)value) < TimeSpan.Zero) ? "-" : "") + ((TimeSpan)value).ToString(@"mm\:ss");
        }
        else if (time < 0)
        {
            return TrainDelay.InAdvance + "  " + ((((TimeSpan)value) < TimeSpan.Zero) ? "-" : "") + ((TimeSpan)value).ToString(@"mm\:ss");
        }
        else
        {
            return TrainDelay.OnTime + "  " + ((((TimeSpan)value) < TimeSpan.Zero) ? "-" : "") + ((TimeSpan)value).ToString(@"mm\:ss");
        }
    }

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

public enum TrainDelay
{
    OnTime,
    Delayed,
    InAdvance
}

I have tried this using DataTrigger in this XAML :

<TextBlock Name="tb" >
    <TextBlock.Style>
        <Style TargetType="TextBlock">
            <Setter Property="Text" Value="defaultDelay"/>
            <Style.Triggers>
                <DataTrigger Binding="{Binding ElementName=tb, Path=TrainDelay, Converter={StaticResource TimeSpanFormatConverter}}" Value="Delayed">
                    <Setter  Property="Foreground" Value="Red"/>
                    <Setter Property="Text" Value="{Binding TrainDelay, Converter={StaticResource TimeSpanFormatConverter}}"/>
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </TextBlock.Style>
</TextBlock>

I'm still not having the right result !

I'm Beginner in C# WPF programming , I need help to implement this or maybe have more explanations to really understand the problem

What this Binding does, is it goes and finds the element named tb , and looks on that element for a property named TrainDelay . Right there it fails, because TextBlock has no property by that name. TrainDelay is a property of a viewmodel, not of the control.

<DataTrigger 
    Binding="{Binding ElementName=tb, Path=TrainDelay, Converter={StaticResource TimeSpanFormatConverter}}" 
    Value="Delayed">

If you want to trigger on the "delayedness" of the train, you'll need another converter to convert the TrainDelay property into just the enum. Comparing "Delayed" to your formatted time string will never work.

That new converter can look like this. It's just a simplified version of the other one. While I'm at it, I'm going to rewrite your converter to simplify it and remove a lot of redundant code. Redundant code is a bad idea: At first, it's just clutter. Then somebody comes along to maintain the thing a year later, and they waste some time confirming that those three subexpressions are really identical after all. Next year somebody else changes two of them. A year after that, somebody needs to make another change and mistakenly assumes the third one was supposed to be different. Meanwhile, somebody else copied and pasted the whole mess, and now you've got more problems.

public class TimeToDelayConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        int.TryParse(value.ToString(), out int time);
        var span = TimeSpan.FromSeconds(time);

        if (string.IsNullOrWhiteSpace(value.ToString()) || span.Equals(TimeSpan.MinValue))
        {
            return null;
        }
        else
        {
            return TimeSpanFormatConverter.SecondsToDelay(time);
        }
    }

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

public class TimeSpanFormatConverter : IValueConverter
{
    public static TrainDelay SecondsToDelay(int time)
    {
        if (time > 0)
        {
            return TrainDelay.Delayed;
        }
        else if (time < 0)
        {
            return TrainDelay.InAdvance;
        }
        else
        {
            return TrainDelay.OnTime;
        }
    }

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        int.TryParse(value.ToString(), out int time);

        //  Don't assign this back to value. Assign it to a new variable that's properly 
        //  typed, so you don't need to cast it. 
        var span = TimeSpan.FromSeconds(time);

        if (string.IsNullOrWhiteSpace(value.ToString()) || span.Equals(TimeSpan.MinValue))
        {
            return "––:––";
        }
        else
        {
            //  No need to copy and paste the same code three times. 
            var timeStr = ((span < TimeSpan.Zero) ? "-" : "") + span.ToString(@"mm\:ss");
            return $"{SecondsToDelay(time)}  {timeStr}";
        }
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}
public enum TrainDelay
{
    OnTime,
    Delayed,
    InAdvance
}

And then your trigger looks like this. Note that it's using a different converter than before.

<DataTrigger 
    Binding="{Binding TrainDelay, Converter={StaticResource TimeToDelayConverter}}" 
    Value="Delayed">

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM