Comment formater TimeSpan en XAML

92

J'essaie de formater un bloc de texte lié à une TimeSpanpropriété. Cela fonctionne si la propriété est de type DateTimemais échoue s'il s'agit d'un fichier TimeSpan. Je peux le faire en utilisant un convertisseur. Mais j'essaie de savoir s'il existe des alternatives.

Exemple de code:

public TimeSpan MyTime { get; set; }

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

Xaml

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

Je m'attends à ce que le bloc de texte affiche seulement les heures et les minutes. Mais il apparaît comme:

19: 10: 46.8048860

biju
la source
Vous souvenez-vous de la version de .Net que vous utilisiez en 2010? J'ai un problème similaire avec Windows Phone XAML: stackoverflow.com/q/18679365/1001985
McGarnagle
Remarque: Le {} au début de tous les formats est une séquence d'échappement, pas un spécificateur de format. Cela oblige XAML à tolérer d'autres crochets dans le format, sans nécessiter de barres obliques inverses.
Grault

Réponses:

88

Dans .NET 3.5, vous pouvez utiliser un MultiBinding à la place

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

Mettre à jour
Pour répondre aux commentaires.

Pour vous assurer de générer 2 chiffres même si les heures ou les minutes sont compris entre 0 et 9, vous pouvez utiliser {0:00} au lieu de {0}. Cela garantira que la sortie pour l'heure 12:01 est 12:01 au lieu de 12: 1.
Si vous voulez afficher 01:01 comme 1:01, utilisezStringFormat="{}{0}:{1:00}"

Et la mise en forme conditionnelle peut être utilisée pour supprimer le signe négatif pendant quelques minutes. Au lieu de {1:00}, nous pouvons utiliser {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
la source
@chibacity: Merci! J'ai déjà crédité votre réponse donc je ne peux pas la refaire :) Mais j'ai mis la question en favoris afin que je puisse retrouver votre solution si jamais j'en avais besoin! Très bien aussi
Fredrik Hedblad
1
Est-ce que cela ne produirait pas "10: 1" ou "4: 9" si la partie des minutes n'a qu'un seul chiffre?
Cygon
@Cygon: voir ma réponse mise à jour pour savoir comment résoudre ce problème. Utilisez {0: D2} au lieu de {0}
Fredrik Hedblad
Cela génère "-07: -12" pour une durée négative de 7 heures et 12 minutes. si la durée est de moins 7 heures, la sortie sera "-07: 00". Mais dès qu'il y a une minute non nulle sur une durée négative, le moins est ajouté .Hoursainsi qu'à.Minutes
tzippy
@FredrikHedblad Je veux afficher TotalMinutesau lieu d'une Minutespartie des minutes (pour afficher les intervalles de temps les plus longs de 1 heure). Mais la TotalMinutespropriété est au format double, donc la liaison à l'aide de la <Binding Path="MyTime.TotalMinutes" />sortie arrondie, ce qui est mauvais - je dois afficher une valeur tronquée au lieu d'arrondir. Il est possible d'y parvenir sans utiliser un convertisseur de valeur personnalisé pour tronquer double en int?
Dominik Palo
140

La chaîne de format est destinée à fonctionner sur un DateTime, pas sur un TimeSpan.

Vous pouvez modifier votre code pour travailler avec DateTime.Now place. Votre xaml va bien:

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

Mettre à jour

Et à partir du format .Net 4 a TimeSpancomme suit:

<TextBlock Text="{Binding MyTime,StringFormat=hh\\:mm}"/>
Tim Lloyd
la source
Oui ... Mais je cherche un moyen de formater une valeur Timespan.
biju
1
Je filtre ma partie de temps à partir d'une collection de dates, en prenant distinct, en triant..blah..it la façon dont ma logique va
biju
@biju J'ai mis à jour l'exemple avec une chaîne de format pour TimeSpan.
Tim Lloyd
2
Je ne sais pas si je fais quelque chose de mal..mais cela ne fonctionne toujours pas pour moi ici.VisualStudio 2008, Framework 3.5
biju
1
C'est la bonne réponse, pas celle indiquée ci-dessus. Même pour dot net 3.5, utilisez un convertisseur au lieu de la réponse suggérée.
MikeKulls
45

Juste pour ajouter au pool, j'utilise avec succès cette liaison pour afficher un TimeSpan dans une application WPF de production:

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

J'ai essayé de corriger les contre-obliques :)

Cygone
la source
5
Si vous voulez aller aux fractions de seconde, vous devez également échapper la virgule: {0: hh \\: mm \\: ss \\.
Ffff

StringFormat = \ {0: hh \\: mm \\: ss \\. Fff \}
Stepan Ivanenko
Ma grande erreur tout le temps était que j'utilisais H comme une chaîne de format DateTime. Mais évidemment il n'y a pas de format 12/24 pour TimeSpan ...
M Stoerzel
22

StringFormatdoit être sous la forme d'une chaîne de format. Dans ce cas, cela ressemblerait à:

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

Remarque: si vous souhaitez afficher le nombre total d'heures et de minutes et que la durée est supérieure à 24 heures, il y a une mise en garde avec votre approche: voici une solution de contournement .

Peter Lillevold
la source
@biju - syntaxe mise à jour. Il manquait des guillemets simples autour de la valeur StringFormat.
Peter Lillevold
Et oui, comme le montre l'exemple @chibacity, un double \ est nécessaire pour échapper au:
Peter Lillevold
1
et en effet, cela ne fonctionne que dans .Net 4.0! La chaîne de format est totalement ignorée dans .Net 3.5.
Peter Lillevold
2
Notez également que cela fonctionne avec un TextBlock mais PAS (!) Avec un Label.
Shackles
2
@Shackles StringFormat est utilisé uniquement si la cible du Binding est une propriété de type String. Label.Content est Object, donc il est ignoré. TextBlock.Text est une chaîne, elle est donc utilisée.
15ee8f99-57ff-4f92-890c-b56153
16

Pour les liaisons multiples, vous devez faire attention depuis .NET 4.

Un bref aperçu ci-dessous, testé avec .NET 4.6:

Reliure régulière:

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

Reliure multiple:

<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 vous pouvez utiliser " au lieu de " dans le multibinding:

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

Remarque: en utilisant StringFormat = "{} {0: hh \: \: mm \: ss} -> {1: hh \: mm \: ss}" sera pas travailler sur un MultiBinding, cela se traduira par un résultat blanc.

juFo
la source
13

Je suis conscient que cette question est ancienne maintenant, mais je suis surpris que personne n'ait suggéré ce simple StringFormatqui fonctionnera TimeSpandirectement sur un :

<TextBlock Text="{Binding MyTime, StringFormat={}{0:hh}:{0:mm}, FallbackValue=00:00}"/>
Sheridan
la source
2
Beaucoup de confusion à ce sujet. On dirait que la syntaxe a peut-être changé avec .NET 4.
McGarnagle
12

WPF dans .NET 4 a désormais une durée à partir de chaînes http://msdn.microsoft.com/en-us/library/ee372286.aspx

J'utilise ce qui suit <TextBlock FontSize="12" Text="{Binding Path=TimeLeft, StringFormat={}{0:g}}" />

Ira
la source
1
Fonctionne en fait dans .NET 4-4.5. Aucune autre solution de ce fil ne le fait.
erodewald
C'était peut-être vrai en février 2012, mais ce n'est plus le cas.
Sheridan
8

Si vous souhaitez utiliser StringFormat dans une étiquette qui utilise la propriété Content, vous pouvez utiliser ContentStringFormat pour mettre en forme votre période:

<Label Content={Binding MyTimespan}" ContentStringFormat="{}{0:hh}:{0:mm}:{0:ss}"
mcflux101
la source
Ce que vous indiquez dans votre réponse mérite une double mise en évidence: dans les contrôles XAML qui utilisent la Contentpropriété (c'est-à-dire pas la Textpropriété comme, par exemple, a TextBlock), la propriété ContentStringFormat doit être utilisée. La spécification StringFormatdans le cadre de la liaison ne fonctionnera pas.
Informagic
2

TimeSpan StringFormat avec des millisecondes:

<TextBlock Text="{Binding MyTime, StringFormat=\{0:hh\\:mm\\:ss\\.fff\}}"/>
Stépan Ivanenko
la source