Як відформатувати 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
McGarnagle

Примітка: {} на початку всіх форматів є послідовністю екранування, а не специфікатором формату. Це змушує 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}
Фредрік Хедблад

Це виводить "-07: -12" для від'ємного часу 7 годин 12 хвилин. якщо тривалість мінус 7 годин, результат буде "-07: 00". Але як тільки з’являється ненульова хвилина від’ємної тривалості, мінус додається .Hoursтак само, як і.Minutes
tzippy

@FredrikHedblad Я хочу показувати TotalMinutesзамість частини Minutesхвилини (щоб показати часовий проміжок, довший за 1 годину). Але TotalMinutesвластивість у подвійному форматі, тому прив'язка з використанням <Binding Path="MyTime.TotalMinutes" />виводить округлений вихід, що погано - мені потрібно показувати усічене значення замість округленого. Це можна досягти, не використовуючи користувальницьке значення ковентера для обрізання double до int?
Домінік Пало

140

Рядок форматування призначений для роботи з а 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

45

Щоб лише додати до пулу, я успішно використовую це прив’язку для відображення TimeSpan у виробничій програмі WPF:

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

Взяв кілька спроб, щоб правильно зробити зворотні риски :)


5
Якщо ви хочете перейти на частки секунди, вам також потрібно уникнути коми: {0: hh \\: mm \\: ss \\.
Ffff

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, але НЕ (!) З міткою.
Кайдани

2
@Shackles StringFormat використовується лише в тому випадку, якщо ціль Прив'язки є властивістю типу String. Label.Content - це Object, тому він ігнорується. TextBlock.Text - це рядок, тому він використовується.
15ee8f99-57ff-4f92-890c-b56153

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, це призведе до порожнього результату.


13

Я усвідомлюю, що це питання вже старе, але я здивований, що ніхто не запропонував такого простого, StringFormatякий буде працювати TimeSpanбезпосередньо:

<TextBlock Text="{Binding MyTime, StringFormat={}{0:hh}:{0:mm}, FallbackValue=00:00}"/>

2
Багато плутанини навколо цього. Здається, можливо синтаксис змінився з .NET 4.
McGarnagle

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 року, але це вже не так.
Шерідан

8

Якщо ви хочете використовувати StringFormat у мітці, яка використовує властивість Content, ви можете використовувати ContentStringFormat для форматування вашого часового проміжку:

<Label Content={Binding MyTimespan}" ContentStringFormat="{}{0:hh}:{0:mm}:{0:ss}"

Те, що ви вказали у своїй відповіді, заслуговує на подвійне виділення: у елементах керування XAML, які використовують Contentвластивість (тобто не Textвластивість, як, наприклад, а TextBlock), властивість ContentStringFormat повинна використовуватися. Вказівка StringFormatяк частина прив’язки не буде працювати.
Informagic

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.