Cómo formatear TimeSpan en XAML

92

Estoy intentando formatear un bloque de texto que está vinculado a una TimeSpanpropiedad. Funciona si la propiedad es de tipo DateTimepero falla si es un TimeSpan. Puedo hacerlo usando un convertidor. Pero estoy tratando de averiguar si hay alternativas.

Código de muestra:

public TimeSpan MyTime { get; set; }

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

Xaml

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

Espero que el bloque de texto muestre solo horas y minutos. Pero se muestra como:

19: 10: 46.8048860

biju
fuente
¿Recuerda qué versión de .Net estaba ejecutando en 2010? Tengo un problema similar con Windows Phone XAML: stackoverflow.com/q/18679365/1001985
McGarnagle
Nota: El {} al principio de todos los formatos es una secuencia de escape, no un especificador de formato. Hace que XAML tolere más corchetes en el formato, sin requerir barras invertidas.
Grault

Respuestas:

88

En .NET 3.5, podría usar un MultiBinding en su lugar

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

Actualizar
Para responder a los comentarios.

Para asegurarse de generar 2 dígitos, incluso si las horas o los minutos son 0-9, puede usar {0:00} en lugar de {0}. Esto asegurará que la salida para la hora 12:01 sea 12:01 en lugar de 12: 1.
Si desea generar 01:01 como 1:01 useStringFormat="{}{0}:{1:00}"

Y el formato condicional se puede utilizar para eliminar el signo negativo durante minutos. En lugar de {1:00} podemos usar {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
fuente
@chibacity: ¡Gracias! Ya le di el crédito a tu respuesta, así que no puedo volver a hacerlo :) ¡Pero marqué la pregunta como favorita para poder encontrar tu solución si alguna vez la necesitaba! Muy bonito también
Fredrik Hedblad
1
¿No saldría esto "10: 1" o "4: 9" si la parte de los minutos tiene sólo un dígito?
Cygon
@Cygon: Vea mi respuesta actualizada sobre cómo solucionar esto. Usa {0: D2} en lugar de {0}
Fredrik Hedblad
Esto genera "-07: -12" para una duración de tiempo negativa de 7 horas y 12 minutos. si la duración es menos 7 horas, la salida sería "-07: 00". Pero tan pronto como hay un minuto distinto de cero con una duración negativa, el signo menos se agrega a .Hoursy a.Minutes
tzippy
@FredrikHedblad Quiero mostrar en TotalMinuteslugar de una Minutesparte de minutos (para mostrar los intervalos de tiempo más largos que 1 hora). Pero la TotalMinutespropiedad está en formato doble, por lo que la vinculación con el <Binding Path="MyTime.TotalMinutes" />produce una salida redondeada, lo cual es malo: necesito mostrar un valor truncado en lugar de redondeado. ¿Es posible lograrlo sin usar un convertidor de valor personalizado para truncar de doble a int?
Dominik Palo
140

La cadena de formato está diseñada para funcionar en a DateTime, no en TimeSpan.

En su lugar, podría cambiar su código para trabajar DateTime.Now. Tu xaml está bien:

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

Actualizar

Y desde el formato .Net 4 a de la TimeSpansiguiente manera:

<TextBlock Text="{Binding MyTime,StringFormat=hh\\:mm}"/>
Tim Lloyd
fuente
Sí ... Pero estoy buscando alguna forma de formatear un valor de período de tiempo.
biju
1
Estoy filtrando mi parte de tiempo de una colección de fechas, tomando distintas, ordenando ... blah ... es la forma en que va mi lógica
biju
@biju He actualizado la muestra con una cadena de formato para TimeSpan.
Tim Lloyd
2
No sé si estoy haciendo algo mal ... pero todavía no me funciona aquí.VisualStudio 2008, Framework 3.5
biju
1
Esta es la respuesta correcta, no la marcada arriba. Incluso para dot net 3.5 use un convertidor en lugar de la respuesta sugerida.
MikeKulls
45

Solo para agregar al grupo, estoy usando con éxito este enlace para mostrar un TimeSpan en una aplicación WPF de producción:

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

Tomó algunos intentos para obtener las barras invertidas correctas :)

Cygon
fuente
5
Si desea ir a fracciones de segundo, también debe escapar de la coma: {0: hh \\: mm \\: ss \\.
Ffff

StringFormat = \ {0: hh \\: mm \\: ss \\. Fff \}
Stepan Ivanenko
Mi gran error todo el tiempo fue que usé H como una cadena de formato DateTime. Pero obviamente no hay un formato 12/24 para TimeSpan ...
M Stoerzel
22

StringFormatdebe tener la forma de una cadena de formato. En este caso, se vería así:

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

Nota: si desea mostrar el número total de horas y minutos y el intervalo de tiempo es superior a 24 horas, hay una advertencia con su enfoque: aquí hay una solución .

Peter Lillevold
fuente
@biju: sintaxis actualizada. Faltaban comillas simples alrededor del valor StringFormat.
Peter Lillevold
Y sí, como muestra el ejemplo de @chibacity, se requiere un doble \ para escapar del:
Peter Lillevold
1
y de hecho, ¡esto solo funciona en .Net 4.0! La cadena de formato se ignora totalmente en .Net 3.5.
Peter Lillevold
2
También tenga en cuenta que esto funciona con TextBlock pero NO (!) Con Label.
Grilletes
2
@Shackles StringFormat se usa solo si el destino del enlace es una propiedad de tipo String. Label.Content es Object, por lo que se ignora. TextBlock.Text es una cadena, por lo que se usa.
15ee8f99-57ff-4f92-890c-b56153
16

Para los enlaces múltiples, debe prestar atención ya que .NET 4.

Una breve descripción a continuación, probada con .NET 4.6:

Encuadernación regular:

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

Enlace múltiple:

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

o puede usar "en lugar de " en el enlace múltiple:

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

Nota: el uso de StringFormat = "{} {0: hh \: \: mm \: ss} -> {1: hh \: mm \: ss}" va a no trabajar en un MultiBinding, esto dará lugar a un resultado en blanco.

juFo
fuente
13

Soy consciente de que esta pregunta es antigua ahora, pero me sorprende que nadie sugiera esto simple StringFormatque funcionará TimeSpandirectamente:

<TextBlock Text="{Binding MyTime, StringFormat={}{0:hh}:{0:mm}, FallbackValue=00:00}"/>
Sheridan
fuente
2
Mucha confusión en torno a esto. Parece que tal vez la sintaxis cambió con .NET 4.
McGarnagle
12

WPF en .NET 4 ahora tiene un intervalo de tiempo de cadenas http://msdn.microsoft.com/en-us/library/ee372286.aspx

Estoy usando lo siguiente <TextBlock FontSize="12" Text="{Binding Path=TimeLeft, StringFormat={}{0:g}}" />

Ira
fuente
1
Realmente funciona en .NET 4-4.5. Ninguna otra solución en este hilo lo hace.
Erodewald
Quizás eso fuera cierto en febrero de 2012, pero ya no lo es.
Sheridan
8

Si desea usar StringFormat en una etiqueta que usa la propiedad Content, puede usar ContentStringFormat para formatear su intervalo de tiempo:

<Label Content={Binding MyTimespan}" ContentStringFormat="{}{0:hh}:{0:mm}:{0:ss}"
mcflux101
fuente
Lo que indica en su respuesta merece un doble resaltado: en los controles XAML que usan la Contentpropiedad (es decir, no la Textpropiedad como, por ejemplo, a TextBlock), se ContentStringFormat debe usar la propiedad . Especificar StringFormatcomo parte del enlace no funcionará.
Informagic
2

TimeSpan StringFormat con milisegundos:

<TextBlock Text="{Binding MyTime, StringFormat=\{0:hh\\:mm\\:ss\\.fff\}}"/>
Stepan Ivanenko
fuente