Come formattare TimeSpan in XAML


92

Sto provando a formattare un blocco di testo che è associato a una TimeSpanproprietà. Funziona se la proprietà è di tipo DateTimema fallisce se è un file TimeSpan. Posso farlo usando un convertitore. Ma sto cercando di scoprire se ci sono alternative.

Codice di esempio:

public TimeSpan MyTime { get; set; }

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

Xaml

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

Mi aspetto che il blocco di testo mostri solo ore e conio. Ma sta mostrando come:

19: 10: 46.8048860


Ricordi su quale versione di .Net stavi eseguendo nel 2010? Sto avendo un problema simile con Windows Phone XAML: stackoverflow.com/q/18679365/1001985
McGarnagle

Nota: la {} all'inizio di tutti i formati è una sequenza di escape, non un identificatore di formato. Fa sì che XAML tolleri ulteriori parentesi nel formato, senza richiedere barre rovesciate.
Grault

Risposte:


88

In .NET 3.5 è possibile utilizzare invece un MultiBinding

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

Aggiorna
Per rispondere ai commenti.

Per assicurarti di produrre 2 cifre anche se le ore o i minuti sono 0-9, puoi utilizzare {0:00} invece di {0}. Questo assicurerà che l'output per l'ora 12:01 sia 12:01 invece di 12: 1.
Se vuoi produrre 01:01 come 1:01 usaStringFormat="{}{0}:{1:00}"

E la formattazione condizionale può essere utilizzata per rimuovere il segno negativo per minuti. Invece di {1:00} possiamo usare {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: grazie! Ho già accreditato la tua risposta quindi non posso farlo di nuovo :) Ma ho preferito la domanda in modo da poter trovare la tua soluzione se mai ne avessi avuto bisogno! Molto bello anche
Fredrik Hedblad

1
Non produrrebbe "10: 1" o "4: 9" se la parte dei minuti ha solo una cifra?
Cygon

@Cygon: vedi la mia risposta aggiornata per come risolvere questo problema. Usa {0: D2} invece di {0}
Fredrik Hedblad

Questo restituisce "-07: -12" per una durata temporale negativa di 7 ore e 12 minuti. se la durata è meno 7 ore, l'output sarà "-07: 00". Ma non appena c'è un minuto diverso da zero su una durata negativa, il segno meno viene aggiunto a.Hours così come a.Minutes
tzippy

@FredrikHedblad Voglio mostrare TotalMinutesinvece che Minutescome parte dei minuti (per mostrare i periodi di tempo più lunghi di 1 ora). MaTotalMinutes proprietà è in formato doppio, quindi l'associazione utilizzando il <Binding Path="MyTime.TotalMinutes" />produce un output arrotondato, il che è negativo: devo mostrare un valore troncato invece di arrotondato. È possibile ottenerlo senza utilizzare un convertitore di valori personalizzato per troncare double a int?
Dominik Palo

139

La stringa di formato è destinata a funzionare su un DateTime, non su un file TimeSpan.

Potresti invece cambiare il tuo codice con cui lavorare DateTime.Now. Il tuo xaml va bene:

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

Aggiornare

E da .Net 4 formato a TimeSpancome segue:

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

Sì ... Ma sto cercando un modo per formattare un valore Timespan.
biju

1
Sto filtrando la mia parte di tempo da una raccolta di date, prendendo distinti, ordinando..blah..è il modo in cui va la mia logica
biju

@biju Ho aggiornato l'esempio con una stringa di formato per TimeSpan.
Tim Lloyd

2
Non so se sto facendo qualcosa di sbagliato ... ma ancora non funziona per me qui.VisualStudio 2008, Framework 3.5
biju

1
Questa è la risposta corretta, non quella indicata sopra. Anche per dot net 3.5 usa un convertitore al posto della risposta suggerita.
MikeKulls

44

Solo per aggiungere al pool, sto usando con successo questa associazione per visualizzare un TimeSpan in un'app WPF di produzione:

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

Ci sono voluti alcuni tentativi per ottenere le barre rovesciate corrette :)


5
Se vuoi andare a frazioni di secondo devi anche evitare la virgola: {0: hh \\: mm \\: ss \\.
Ffff

StringFormat = \ {0: hh \\: mm \\: ss \\. Fff \}
Stepan Ivanenko

Il mio grande errore è stato sempre che ho usato H come la stringa di formato DateTime. Ma ovviamente non esiste un formato 12/24 per TimeSpan ...
M Stoerzel

22

StringFormatdeve essere nella forma di una stringa di formato. In questo caso sarebbe simile:

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

Nota: se desideri visualizzare il numero totale di ore e minuti e l'intervallo di tempo è maggiore di 24 ore, c'è un avvertimento con il tuo approccio: ecco una soluzione alternativa .


@biju - sintassi aggiornata. Mancavano virgolette singole attorno al valore StringFormat.
Peter Lillevold

E sì, come mostra l'esempio di @chibacity, è necessaria una doppia \ per sfuggire a:
Peter Lillevold

1
e in effetti, questo funziona solo in .Net 4.0! La stringa di formato è totalmente ignorata in .Net 3.5.
Peter Lillevold

2
Si noti inoltre che questo funziona con un TextBlock ma NON (!) Con un'etichetta.
Grilli

2
@Shackles StringFormat viene utilizzato solo se la destinazione del Binding è una proprietà di tipo String. Label.Content è Object, quindi viene ignorato. TextBlock.Text è una stringa, quindi viene utilizzata.
15ee8f99-57ff-4f92-890c-b56153

16

Per i collegamenti multipli è necessario prestare attenzione poiché .NET 4.

Di seguito una breve panoramica, testata con .NET 4.6:

Legatura regolare:

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

Multi rilegatura:

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

oppure potresti usare " invece di " nel multibinding:

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

Nota: utilizzando StringFormat = "{} {0: hh \: \: mm \: ss} -> {1: hh \: mm \: ss}" sarà non lavoro su una MultiBinding, questo si tradurrà in un risultato vuoto.


13

Sono consapevole che questa domanda è vecchia ora, ma sono sorpreso che nessuno abbia suggerito questo semplice StringFormatche funzionerà TimeSpandirettamente su:

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

2
Molta confusione su questo. Sembra che la sintassi sia cambiata con .NET 4.
McGarnagle


8

Se desideri utilizzare StringFormat in un'etichetta che utilizza la proprietà Content, puoi utilizzare ContentStringFormat per formattare il periodo di tempo:

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

Ciò che dichiari nella tua risposta merita una doppia evidenziazione: nei controlli XAML che utilizzano la Contentproprietà (cioè, non la Textproprietà come, ad esempio, a TextBlock), la proprietà ContentStringFormat deve essere utilizzata. La specifica StringFormatcome parte dell'associazione non funzionerà.
Informagico

2

TimeSpan StringFormat con millisecondi:

<TextBlock Text="{Binding MyTime, StringFormat=\{0:hh\\:mm\\:ss\\.fff\}}"/>
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.