简体   繁体   English

转换器和枚举更改TextBlock的前景颜色

[英]Converter and enum to change Foreground color of TextBlock

I would like to display in a TextBlock my variable TrainDelay in a specific format 我想以特定格式在TextBlock显示我的变量TrainDelay

I used a Converter IntToTimeSpanConverter to format TrainDelay : (mm:ss) 我使用Converter IntToTimeSpanConverter格式化TrainDelay:(mm:ss)

so according to the value of TrainDelay such as: 因此根据TrainDelay的值,例如:

  • Display Delayed (00:23) in red color 以红色显示Delayed (00:23)
  • Display On Time (00:00) in dark color 以深色显示On Time (00:00)
  • Display In Advance (- 00:15) in green color In Advance (- 00:15)绿色In Advance (- 00:15)显示In Advance (- 00:15)

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 : 我已经在此XAML中使用DataTrigger尝试过此操作:

<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 我是C#WPF编程的初学者,需要帮助以实现此目的,或者可能需要更多说明才能真正理解问题

What this Binding does, is it goes and finds the element named tb , and looks on that element for a property named TrainDelay . 该绑定的作用是找到名为tb的元素,然后在该元素上查找名为TrainDelay的属性。 Right there it fails, because TextBlock has no property by that name. 就在那儿失败了,因为TextBlock没有该名称的属性。 TrainDelay is a property of a viewmodel, not of the control. TrainDelay是视图TrainDelay的属性,而不是控件的属性。

<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. 如果要触发火车的“延迟”,则需要另一个转换器将TrainDelay属性转换为枚举。 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">

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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