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.