Como formatar TimeSpan em XAML


92

Estou tentando formatar um bloco de texto vinculado a uma TimeSpanpropriedade. Funciona se a propriedade for do tipo, DateTimemas falhará se for a TimeSpan. Posso fazer isso usando um conversor. Mas estou tentando descobrir se há alternativas.

Código de amostra:

public TimeSpan MyTime { get; set; }

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

Xaml

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

Estou esperando que o bloco de texto mostre apenas horas e minutos. Mas está sendo mostrado como:

19: 10: 46,8048860


Você se lembra de qual versão do .Net você estava executando em 2010? Estou tendo um problema semelhante com o Windows Phone XAML: stackoverflow.com/q/18679365/1001985
— McGarnagle

Nota: O {} no início de todos os formatos é uma sequência de escape, não um especificador de formato. Isso faz com que o XAML tolere mais colchetes no formato, sem exigir barras invertidas.
— Grault

Respostas:


88

No .NET 3.5, você pode usar um MultiBinding em vez

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

Atualizar
Para responder aos comentários.

Para garantir a saída de 2 dígitos, mesmo que as horas ou minutos sejam de 0 a 9, você pode usar {0:00} em vez de {0}. Isso garantirá que a saída para o horário 12:01 seja 12:01 em vez de 12: 1.
Se você deseja produzir 01:01 como 01:01, useStringFormat="{}{0}:{1:00}"

E a formatação condicional pode ser usada para remover o sinal negativo de minutos. Em vez 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>

@chibacity: Obrigado! Já creditei sua resposta, então não posso fazer de novo :) Mas eu adicionei a pergunta aos favoritos para poder encontrar sua solução se eu precisar! Muito bom também
— Fredrik Hedblad

1
Isso não geraria "10: 1" ou "4: 9" se a parte dos minutos tivesse apenas um dígito?
— Cygon

@Cygon: Veja minha resposta atualizada para saber como consertar isso. Use {0: D2} em vez de {0}
— Fredrik Hedblad 01 de

Isso gera "-07: -12" para uma duração negativa de 7 horas e 12 minutos. se a duração for menos 7 horas, a saída será "-07: 00". Mas assim que houver um minuto diferente de zero em uma duração negativa, o menos é anexado a .Hours, bem como a.Minutes
— tzippy

@FredrikHedblad Desejo mostrar em TotalMinutesvez de Minutescomo parte de minutos (para mostrar intervalos de tempo mais longos que 1 hora). Mas a TotalMinutespropriedade está em formato duplo, então a vinculação usando o <Binding Path="MyTime.TotalMinutes" />produz uma saída arredondada, o que é ruim - preciso mostrar o valor truncado em vez de arredondado. É possível fazer isso sem usar um conversor de valor personalizado para truncar double para int?
— Dominik Palo

139

A string de formato se destina a funcionar em um DateTime, não um TimeSpan.

Você pode alterar seu código para trabalhar DateTime.Now. Seu xaml está bom:

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

Atualizar

E do formato .Net 4 a da TimeSpanseguinte forma:

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

Sim ... Mas estou procurando uma maneira de formatar um valor de Timespan.
— biju

1
Estou filtrando minha parte do tempo de uma coleção de datas, separando, classificando ... blah ... é do jeito que minha lógica vai
— biju

@biju Eu atualizei o exemplo com uma string de formato para TimeSpan.
— Tim Lloyd

2
Não sei se estou fazendo algo errado ... mas ainda não está funcionando para mim aqui.VisualStudio 2008, Framework 3.5
— biju

1
Esta é a resposta correta, não aquela marcada acima. Mesmo para o dot net 3.5, use um conversor em vez da resposta sugerida.
— MikeKulls,

44

Apenas para adicionar ao pool, estou usando com sucesso esta ligação para exibir um TimeSpan em um aplicativo WPF de produção:

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

Fiz algumas tentativas para acertar as barras invertidas :)


5
Se você quiser ir para frações de segundo, você precisa escapar da vírgula também: {0: hh \\: mm \\: ss \\.
— Ffff

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

Meu grande erro o tempo todo foi usar H como string de formato DateTime. Mas obviamente não há formato
— 24/12

22

StringFormatdeve estar na forma de uma string de formato. Neste caso, seria semelhante a:

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

Observação: se você deseja exibir o número total de horas e minutos e o intervalo de tempo passa a ser maior que 24 horas, há uma ressalva com sua abordagem: Aqui está uma solução alternativa .


@biju - sintaxe atualizada. Faltavam aspas simples em torno do valor StringFormat.
— Peter Lillevold

E sim, como mostra o exemplo de @chibacity, um \ duplo é necessário para escapar de:
— Peter Lillevold

1
e, de fato, isso só funciona no .Net 4.0! A string de formato é totalmente ignorada em .Net 3.5.
— Peter Lillevold

2
Observe também que isso funciona com um TextBlock, mas NÃO (!) Com um Label.
— Shackles

2
@Shackles StringFormat é usado apenas se o destino de Binding for uma propriedade do tipo String. Label.Content é Object, portanto, é ignorado. TextBlock.Text é uma string, então é usado.
— 15ee8f99-57ff-4f92-890c-b56153

16

Para Multi bindings, você precisa prestar atenção desde .NET 4.

Uma breve visão geral abaixo, testada com .NET 4.6:

Encadernação regular:

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

Multi binding:

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

ou você pode usar "em vez de ' no multibinding:

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

Nota: usando StringFormat = "{} {0: hh \: \: mm \: ss} -> {1: hh \: mm \: ss}" será não trabalho em um MultiBinding, isso irá resultar em um resultado em branco.


13

Estou ciente de que esta questão é antiga agora, mas estou surpreso que ninguém sugeriu este simples StringFormatque funcionará TimeSpandiretamente em:

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

2
Muita confusão em torno disso. Parece que a sintaxe mudou com o .NET 4.
— McGarnagle


8

Se quiser usar StringFormat em um rótulo que usa a propriedade Content, você pode usar ContentStringFormat para formatar seu intervalo de tempo:

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

O que você afirma em sua resposta merece um destaque duplo: em controles XAML que usam a Contentpropriedade (ou seja, não a Textpropriedade como, por exemplo, a TextBlock), a propriedade ContentStringFormat deve ser usada. Especificar StringFormatcomo parte da vinculação não funcionará.
— Informagic

2

TimeSpan StringFormat com milissegundos:

<TextBlock Text="{Binding MyTime, StringFormat=\{0:hh\\:mm\\:ss\\.fff\}}"/>
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.