Конвертер и перечисление для изменения цвета переднего плана TextBlock - PullRequest
0 голосов
/ 26 апреля 2018

Я хотел бы отобразить в TextBlock мою переменную TrainDelay в определенном формате

Я использовал конвертер IntToTimeSpanConverter для форматирования TrainDelay: (мм: сс)

так в соответствии со значением 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
}

Я пробовал это, используя DataTrigger в этом 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>

У меня все еще нет правильного результата!

Я новичок в программировании WPF на C #, мне нужна помощь для реализации этого или, может быть, есть дополнительные объяснения, чтобы действительно понять проблему

1 Ответ

0 голосов
/ 26 апреля 2018

Что делает эта привязка, так это то, что она находит и находит элемент с именем 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">
...