Jak sformatować TimeSpan w XAML

92

Próbuję sformatować blok tekstowy, który jest powiązany z TimeSpanwłaściwością. Działa, jeśli właściwość jest typu, DateTimeale kończy się niepowodzeniem, jeśli jest to TimeSpan. Mogę to zrobić za pomocą konwertera. Ale próbuję się dowiedzieć, czy są jakieś alternatywy.

Przykładowy kod:

public TimeSpan MyTime { get; set; }

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

Xaml

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

Oczekuję, że blok tekstowy pokaże tylko godziny i mięty. Ale pokazuje się jako:

19:10: 46,8048860

biju
źródło
Czy pamiętasz jaką wersję .Net używałeś w 2010 roku? Mam podobny problem z Windows Phone XAML: stackoverflow.com/q/18679365/1001985
McGarnagle,
Uwaga: {} na początku wszystkich formatów jest sekwencją ucieczki, a nie specyfikatorem formatu. Powoduje, że XAML toleruje dalsze nawiasy w formacie, bez konieczności stosowania ukośników odwrotnych.
Grault

Odpowiedzi:

88

W .NET 3.5 można zamiast tego użyć MultiBinding

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

Aktualizacja
Aby odpowiedzieć na komentarze.

Aby mieć pewność, że wypisujesz 2 cyfry, nawet jeśli godziny lub minuty to 0–9, możesz użyć {0:00} zamiast {0}. Zapewni to, że wyjście dla czasu 12:01 to 12:01 zamiast 12: 1.
Jeśli chcesz wypisać 01:01 jako 1:01 użyjStringFormat="{}{0}:{1:00}"

I formatowanie warunkowe może być stosowany do usuwania znak ujemny dla minut. Zamiast {1:00} możemy użyć {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>
Fredrik Hedblad
źródło
@chibacity: Dziękuję! Podałem już Twoją odpowiedź, więc nie mogę zrobić tego ponownie :) Ale dodałem pytanie do ulubionych, aby móc znaleźć Twoje rozwiązanie, jeśli kiedykolwiek będę go potrzebować!
Również
1
Czy nie dałoby to wyniku „10: 1” lub „4: 9”, gdyby część minutowa miała tylko jedną cyfrę?
Cygon
@Cygon: Zobacz moją zaktualizowaną odpowiedź, jak to naprawić. Użyj {0: D2} zamiast {0}
Fredrik Hedblad
Powoduje to wyświetlenie „-07: -12” dla ujemnego czasu trwania 7 godzin i 12 minut. jeśli czas trwania wynosi minus 7 godzin, wynik wyniesie „-07: 00”. Ale jak tylko pojawi się niezerowa minuta na ujemnym czasie trwania, minus jest dodawany do, .Hoursa także do.Minutes
tzippy
@FredrikHedblad Chcę pokazać TotalMinuteszamiast Minutesjako część minut (aby pokazać okresy najdłuższe niż 1 godzina). Ale TotalMinuteswłaściwość jest w formacie podwójnym, więc wiązanie przy użyciu <Binding Path="MyTime.TotalMinutes" />zaokrąglonych danych wyjściowych jest złe - muszę pokazać obciętą wartość zamiast zaokrąglenia. Czy można to osiągnąć bez używania konwertera wartości niestandardowej do obcinania double do int?
Dominik Palo
142

Ciąg formatu ma działać na a DateTime, a nie TimeSpan.

Zamiast tego możesz zmienić swój kod, aby działał DateTime.Now. Twój XAML jest w porządku:

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

Aktualizacja

A z formatu .Net 4 a TimeSpanw następujący sposób:

<TextBlock Text="{Binding MyTime,StringFormat=hh\\:mm}"/>
Tim Lloyd
źródło
Tak ... Ale szukam sposobu, w jaki mogę sformatować wartość przedziału czasu.
biju
1
Filtruję część czasu ze zbioru dat, wybierając odrębne, sortujące ... niebieskie ... tak działa moja logika
biju
@biju Zaktualizowałem próbkę ciągiem formatu dla TimeSpan.
Tim Lloyd
2
Nie wiem, czy robię coś źle, ale nadal mi to nie działa.VisualStudio 2008, Framework 3.5
biju
1
To jest poprawna odpowiedź, a nie ta zaznaczona powyżej. Nawet w przypadku dot net 3.5 użyj konwertera zamiast sugerowanej odpowiedzi.
MikeKulls
45

Aby dodać do puli, pomyślnie używam tego powiązania do wyświetlania TimeSpan w produkcyjnej aplikacji WPF:

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

Podjęto kilka prób, aby uzyskać prawidłowe ukośniki :)

Cygon
źródło
5
Jeśli chcesz przejść do ułamków sekundy, musisz też
pominąć
StringFormat = \ {0: hh \\: mm \\: ss \\. Fff \}
Stepan Ivanenko
Moim wielkim błędem przez cały czas było to, że użyłem H jak ciąg formatu DateTime. Ale oczywiście nie ma formatu 12/24 dla TimeSpan ...
M Stoerzel
22

StringFormatmusi mieć postać ciągu formatu. W tym przypadku wyglądałoby to tak:

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

Uwaga: jeśli chcesz wyświetlić całkowitą liczbę godzin i minut, a przedział czasu jest dłuższy niż 24 godziny, istnieje zastrzeżenie dotyczące Twojego podejścia: Oto obejście .

Peter Lillevold
źródło
@biju - zaktualizowana składnia. Brakowało pojedynczych cudzysłowów wokół wartości StringFormat.
Peter Lillevold
I tak, jak pokazuje przykład @chibacity, podwójne \ jest wymagane, aby uciec przed:
Peter Lillevold
1
i rzeczywiście, działa to tylko w .Net 4.0! Ciąg formatu jest całkowicie ignorowany w .Net 3.5.
Peter Lillevold
2
Zauważ również, że działa to z TextBlock, ale NIE (!) Z Label.
Shackles
2
@Shackles StringFormat jest używany tylko wtedy, gdy obiekt docelowy Binding jest właściwością typu String. Label.Content to Object, więc jest ignorowany. TextBlock.Text jest ciągiem znaków, więc jest używany.
15ee8f99-57ff-4f92-890c-b56153
16

W przypadku powiązań Multi należy zwrócić uwagę, ponieważ .NET 4.

Krótki przegląd poniżej, przetestowany z .NET 4.6:

Zwykłe wiązanie:

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

Wiązanie multi:

<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>

lub możesz użyć zamiast w multibindingu:

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

Uwaga: użycie StringFormat = "{} {0: hh \: \: mm \: ss} -> {1: hh \: mm \: ss}" spowoduje nie praca na MultiBinding, spowoduje to w efekcie pusty.

juFo
źródło
13

Zdaję sobie sprawę, że to pytanie jest stare, ale jestem zaskoczony, że nikt nie zaproponował tego prostego, StringFormatktóre zadziała TimeSpanbezpośrednio na:

<TextBlock Text="{Binding MyTime, StringFormat={}{0:hh}:{0:mm}, FallbackValue=00:00}"/>
Sheridan
źródło
2
Wiele zamieszania wokół tego. Wydaje się, że może składnia zmieniła się w .NET 4.
McGarnagle,
12

WPF w .NET 4 ma teraz przedział czasu z ciągów http://msdn.microsoft.com/en-us/library/ee372286.aspx

Używam następujących <TextBlock FontSize="12" Text="{Binding Path=TimeLeft, StringFormat={}{0:g}}" />

Ira
źródło
1
Właściwie działa w .NET 4-4.5. Żadne inne rozwiązania w tym wątku nie działają.
erodewald
Może tak było w lutym 2012 roku, ale już nie jest.
Sheridan,
10

Jeśli chcesz użyć StringFormat w Label, która używa właściwości Content, możesz użyć ContentStringFormat, aby sformatować swój przedział czasu:

<Label Content={Binding MyTimespan}" ContentStringFormat="{}{0:hh}:{0:mm}:{0:ss}"
mcflux101
źródło
1
To, co podasz w swojej odpowiedzi, zasługuje na podwójne wyróżnienie: w kontrolkach XAML, które używają Contentwłaściwości (tj. Nie Textwłaściwości, jak na przykład a TextBlock), właściwość ContentStringFormat musi być używana. Określanie StringFormatjako część powiązania nie zadziała.
Informagic
3

TimeSpan StringFormat z milisekundami:

<TextBlock Text="{Binding MyTime, StringFormat=\{0:hh\\:mm\\:ss\\.fff\}}"/>
Stepan Ivanenko
źródło