Как отформатировать TimeSpan в XAML

92

Я пытаюсь отформатировать текстовый блок, привязанный к TimeSpanсвойству. Он работает, если свойство имеет тип, DateTimeно не работает, если это свойство TimeSpan. Я могу сделать это с помощью конвертера. Но я пытаюсь выяснить, есть ли альтернативы.

Образец кода:

public TimeSpan MyTime { get; set; }

public Window2()
{
    InitializeComponent();
    MyTime = DateTime.Now.TimeOfDay;
    DataContext = this;
}

Xaml

<TextBlock Text="{Binding MyTime,StringFormat=HH:mm}"/>

Я ожидаю, что в текстовом блоке будут отображаться только часы и минуты. Но это отображается как:

19: 10: 46.8048860

биджу
источник
Вы помните, какую версию .Net вы использовали еще в 2010 году? У меня аналогичная проблема с Windows Phone XAML: stackoverflow.com/q/18679365/1001985
МакГарнаглал 05
Примечание. {} В начале всех форматов - это escape-последовательность, а не спецификатор формата. Это заставляет XAML допускать использование дополнительных скобок в формате без использования обратной косой черты.
Grault

Ответы:

88

В .NET 3.5 вместо этого вы можете использовать MultiBinding

<TextBlock>
    <TextBlock.Text>
        <MultiBinding StringFormat="{}{0}:{1}">
            <Binding Path="MyTime.Hours"/>
            <Binding Path="MyTime.Minutes"/>
        </MultiBinding>
    </TextBlock.Text>
</TextBlock>

Обновление
Чтобы ответить на комментарии.

Чтобы убедиться, что вы выводите 2 цифры, даже если часы или минуты равны 0–9, вы можете использовать {0:00} вместо {0}. Это обеспечит вывод времени 12:01 на 12:01 вместо 12: 1.
Если вы хотите вывести 01:01 как 1:01, используйтеStringFormat="{}{0}:{1:00}"

А условное форматирование можно использовать для удаления отрицательного знака для минут. Вместо {1:00} мы можем использовать {1: 00; 00}

<TextBlock>
    <TextBlock.Text>
        <MultiBinding StringFormat="{}{0:00}:{1:00;00}">
            <Binding Path="MyTime.Hours" />
            <Binding Path="MyTime.Minutes" />
        </MultiBinding>
    </TextBlock.Text>
</TextBlock>
Фредрик Хедблад
источник
@chibacity: Спасибо! Я уже указывал ваш ответ, поэтому не могу сделать это снова :) Но я поставил вопрос в избранное, чтобы я мог вернуться к вашему решению, если оно мне когда-либо понадобится! Очень хорошо
Фредрик Хедблад
1
Разве это не выводило бы «10: 1» или «4: 9», если бы часть минут состояла только из одной цифры?
Cygon
@Cygon: см. Мой обновленный ответ, чтобы узнать, как это исправить. Используйте {0: D2} вместо {0}
Фредрик Хедблад 01
Это выводит «-07: -12» для отрицательного значения Timeduration 7 часов 12 минут. если продолжительность составляет минус 7 часов, вывод будет «-07: 00». Но как только есть ненулевая минута на отрицательной продолжительности, минус добавляется .Hoursкак и к.Minutes
tzippy
@FredrikHedblad Я хочу показывать, TotalMinutesа не Minutesкак часть минут (чтобы показать самые длинные промежутки времени, что 1 час). Но TotalMinutesсвойство имеет двойной формат, поэтому привязка с использованием <Binding Path="MyTime.TotalMinutes" />дает округленный вывод, что плохо - мне нужно отображать усеченное значение вместо округленного. Можно ли добиться этого без использования специального преобразователя значений для усечения double до int?
Доминик Пало
142

Строка формата предназначена для работы с DateTimeфайлом TimeSpan.

DateTime.NowВместо этого вы можете изменить свой код для работы . Ваш xaml в порядке:

<TextBlock Text="{Binding MyTime,StringFormat=HH:mm}"/>

Обновить

А из .Net 4 форматировать TimeSpanследующим образом:

<TextBlock Text="{Binding MyTime,StringFormat=hh\\:mm}"/>
Тим Ллойд
источник
Да ... Но я ищу способ отформатировать значение Timespan.
biju
1
Я отфильтровываю свою временную часть из коллекции дат, выделяю, сортирую ... мля ... так моя логика идет
biju
@biju Я обновил образец строкой формата для TimeSpan.
Тим Ллойд
2
Я не знаю, делаю ли я что-то не так ... но у меня все еще не работает VisualStudio 2008, Framework 3.5
biju
1
Это правильный ответ, а не тот, который отмечен выше. Даже для dot net 3.5 используйте конвертер вместо предложенного ответа.
MikeKulls 09
45

Просто чтобы добавить в пул, я успешно использую эту привязку для отображения TimeSpan в производственном приложении WPF:

Binding="{Binding Time, Mode=TwoWay, StringFormat=\{0:h\\:mm\}}"

Принял несколько попыток исправить обратную косую черту :)

Cygon
источник
5
Если вы хотите перейти к долям секунды, вам также нужно избегать запятой: {0: hh \\: mm \\: ss \\. Ffff}
Rashack
StringFormat = \ {0: hh \\: mm \\: ss \\. Fff \}
Степан Иваненко
Моя большая ошибка заключалась в том, что я использовал H как строку формата DateTime. Но очевидно, что для TimeSpan не существует формата 12/24 ...
М. Стоерзель,
22

StringFormatдолжен быть в виде строки формата. В этом случае это будет выглядеть так:

<TextBlock Text="{Binding MyTime,StringFormat=`Time values are {0:hh\\:mm}`}"/>

Примечание: если вы хотите отобразить общее количество часов и минут, а временной интервал превышает 24 часа, есть предостережение в отношении вашего подхода: вот обходной путь .

Питер Лиллевольд
источник
@biju - обновлен синтаксис. Отсутствуют одинарные кавычки вокруг значения StringFormat.
Питер Лиллевольд
И да, как показывает пример @chibacity, двойной \ требуется, чтобы избежать:
Питер Лиллевольд
1
и действительно, это работает только в .Net 4.0! Строка формата полностью игнорируется в .Net 3.5.
Питер Лиллевольд
2
Также обратите внимание, что это работает с TextBlock, но НЕ (!) С Label.
Shackles
2
@Shackles StringFormat используется только в том случае, если целью Binding является свойство типа String. Label.Content - это Object, поэтому игнорируется. TextBlock.Text - это строка, поэтому она используется.
15ee8f99-57ff-4f92-890c-b56153 07
16

На привязки Multi нужно обращать внимание, начиная с .NET 4.

Ниже приведен краткий обзор, протестированный с .NET 4.6:

Обычная привязка:

<TextBlock Text="{Binding Start, StringFormat='{}{0:hh\\:mm\\:ss}'}" />

Мульти переплет:

<TextBlock.Text>
    <MultiBinding StringFormat="{}{0:hh':'mm':'ss} -> {1:hh':'mm':'ss}">
        <Binding Path="Start" Mode="OneWay" UpdateSourceTrigger="PropertyChanged" />
        <Binding Path="End" Mode="OneWay" UpdateSourceTrigger="PropertyChanged" />
    </MultiBinding>
</TextBlock.Text>

или вы можете использовать " вместо " в мульти-привязке:

<MultiBinding StringFormat='{}{0:hh":"mm":"ss} -> {1:hh":"mm":"ss}'>

Примечание. Использование StringFormat = "{} {0: hh \: \: mm \: ss} -> {1: hh \: mm \: ss}" не будет работать с MultiBinding, это приведет к пустому результату.

juFo
источник
13

Я знаю, что это старый вопрос, но я удивлен, что никто не предложил этот простой, StringFormatкоторый будет работать TimeSpanнапрямую:

<TextBlock Text="{Binding MyTime, StringFormat={}{0:hh}:{0:mm}, FallbackValue=00:00}"/>
Шеридан
источник
2
Вокруг этого много путаницы. Похоже, синтаксис изменился в .NET 4.
МакГарнаглал 05
12

WPF в .NET 4 теперь имеет временной промежуток из строк http://msdn.microsoft.com/en-us/library/ee372286.aspx

Я использую следующие <TextBlock FontSize="12" Text="{Binding Path=TimeLeft, StringFormat={}{0:g}}" />

Ира
источник
1
Фактически работает в .NET 4-4.5. Никаких других решений в этой теме нет.
erodewald
Возможно, это было правдой в феврале 2012 года, но теперь это не так.
Шеридан
10

Если вы хотите использовать StringFormat в метке, которая использует свойство Content, вы можете использовать ContentStringFormat для форматирования своего временного интервала :

<Label Content={Binding MyTimespan}" ContentStringFormat="{}{0:hh}:{0:mm}:{0:ss}"
mcflux101
источник
1
То, что вы указываете в своем ответе, заслуживает двойного выделения: в элементах управления XAML, которые используют Contentсвойство (т. Е. Не Textсвойство, как, например, a TextBlock), свойство ContentStringFormat должно использоваться. Указать StringFormatкак часть привязки не получится.
Informagic
3

TimeSpan StringFormat с миллисекундами:

<TextBlock Text="{Binding MyTime, StringFormat=\{0:hh\\:mm\\:ss\\.fff\}}"/>
Степан Иваненко
источник