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

时间:2018-04-26 19:43:57

标签: c# wpf xaml datatrigger

我想以TextBlock我的变量TrainDelay以特定格式显示

我使用了转换器IntToTimeSpanConverter来格式化TrainDelay:(mm:ss)

所以根据TrainDelay的值如:

  • 以红色显示Delayed (00:23)
  • 以深色显示On Time (00:00)
  • 以绿色显示In Advance (- 00:15)

一些代码:

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
}

我在此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>

我还没有得到正确的结果!

我是C#WPF编程的初学者,我需要帮助来实现这一点,或者可能有更多解释来真正理解问题

1 个答案:

答案 0 :(得分:0)

这个Binding的作用是,它会找到名为tb的元素,并在该元素上查找名为TrainDelay的属性。它就在那里失败,因为TextBlock没有该名称的属性。 TrainDelay是视图模型的属性,而不是控件的属性。

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

如果要触发列车的“延迟”,则需要另一个转换器将TrainDelay属性转换为枚举。将“延迟”与格式化的时间字符串进行比较将永远不会起作用。

新转换器看起来像这样。它只是另一个的简化版本。当我在这里时,我将重写你的转换器以简化它并删除大量冗余代码。冗余代码是一个坏主意:起初,它只是杂乱无章。然后有人在一年后来维持这件事,他们浪费时间确认这三个子表达式毕竟是完全相同的。明年其他人改变了其中两个。一年之后,有人需要做出另一个改变而错误地认为第三个是假设是不同的。与此同时,有人复制并粘贴了整个烂摊子,现在你遇到了更多问题。

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
}

然后你的触发器就像这样。请注意,它使用不同的转换器

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