如何在XAML中格式化TimeSpan

114

我正在尝试格式化一个绑定到TimeSpan属性的文本块。如果该属性是DateTime类型,则可以正常工作,但如果是TimeSpan类型,则失败。我可以使用转换器完成它,但我正在尝试找出是否有其他替代方法。

示例代码:

public TimeSpan MyTime { get; set; }

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

Xaml

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

我希望文本块只显示小时和分钟,但是它显示为:

19:10:46.8048860


你还记得在2010年时你所使用的.Net版本吗?我现在在Windows Phone XAML上遇到了类似的问题:https://dev59.com/YHbZa4cB1Zd3GeqPHpgz - McGarnagle
注意:所有格式的开头的{}都是转义序列,而不是格式说明符。它使XAML容忍格式中的进一步括号,而不需要反斜杠。 - Grault
11个回答

162

格式化字符串是用于 DateTime 的,而不是 TimeSpan

您可以将代码更改为使用 DateTime.Now。您的 XAML 是正确的:

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

更新

.Net 4开始,可以按以下方式将TimeSpan格式化:

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

1
我正在从一组日期中筛选出时间部分,进行去重、排序等操作...这是我的逻辑方式。 - biju
@biju 我已经更新了示例,添加了TimeSpan的格式字符串。 - Tim Lloyd
2
我不知道我是否做错了什么,但在这里对我仍然没有用。Visual Studio 2008,Framework 3.5。 - biju
1
这是正确答案,而不是上面标记的那个。即使对于dot net 3.5也要使用转换器,而不是建议的答案。 - MikeKulls
@MikeKulls:请查看我的更新答案。在StringFormat中使用D2,即使分钟数为0-9,也始终可以获得两位数字。 - Fredrik Hedblad
显示剩余5条评论

98

在 .NET 3.5 中,您可以使用 MultiBinding 替代

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

更新
回答评论。

为了确保输出的时间为两位数,即使小时或分钟是0-9,你可以使用{0:00}代替{0}。这将确保时间12:01的输出为12:01而不是12:1。
如果您想将01:01输出为1:01,请使用StringFormat="{}{0}:{1:00}"

并且可以使用条件格式化来删除分钟的负号。我们可以使用{1:00;00}而不是{1:00}。

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

@chibacity:谢谢!我已经给你的答案点了赞,所以不能再点了 :) 但我收藏了这个问题,以便将来需要时可以找到你的解决方案!非常好。 - Fredrik Hedblad
1
如果分钟部分只有一位数字,那么这个输出会是“10:1”或者“4:9”吗? - Cygon
@Cygon:请查看我的更新答案以了解如何修复此问题。使用{0:D2}而不是{0}。 - Fredrik Hedblad
对于负的时间持续7小时12分钟,这将输出“-07:-12”。如果持续时间为负7小时,则输出将为“-07:00”。但是,一旦负持续时间上有非零分钟,减号就会附加到.Hours.Minutes - tzippy
@FredrikHedblad 我想展示 TotalMinutes 而不是 Minutes 作为分钟部分(用于显示长于1小时的时间跨度)。但是 TotalMinutes 属性是以双精度格式表示的,因此使用 <Binding Path="MyTime.TotalMinutes" /> 进行绑定会产生舍入输出,这是不好的 - 我需要显示截断值而不是舍入值。 有没有可能在不使用自定义值转换器将双精度截断为整数的情况下实现它? - Dominik Palo

53

只是为了增加这个问题的范围,我成功地在一个生产中的WPF应用程序中使用这个绑定来显示一个TimeSpan:

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

花了几次尝试才弄对反斜杠 :)


5
如果您想要显示秒的小数部分,您需要同样转义逗号:{0:hh\:mm\:ss\.ffff}。 - Rashack
2
StringFormat={0:hh\:mm\:ss\.fff} - Stepagrus
我一直犯的大错误是将 H 用作 DateTime 格式字符串。但显然,TimeSpan 没有12/24小时制格式... - M Stoerzel

24

如果您想在使用Content属性的标签中使用StringFormat,可以使用ContentStringFormat来格式化您的时间间隔:

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

3
您在回答中提到的内容值得双重强调:在使用“Content”属性的XAML控件中(例如,不是像“TextBlock”一样使用“Text”属性),必须使用“ContentStringFormat”属性。将“StringFormat”作为绑定的一部分指定将不起作用。 - Informagic

21

StringFormat 必须按照格式字符串的形式提供。在这种情况下,它应该看起来像:

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

注意:如果您想显示总小时数和分钟数,并且时间跨度大于24小时,则您的方法存在一个警告:这里有一个解决方法


@biju - 更新了语法。在StringFormat值周围缺少单引号。 - Peter Lillevold
是的,正如 @chibacity 的示例所示,需要双斜杠来转义冒号。 - Peter Lillevold
1
实际上,这只适用于 .Net 4.0!在 .Net 3.5 中,格式字符串完全被忽略。 - Peter Lillevold
似乎它只能在 .Net 4.0 上运行。在我的情况下,很明显我需要使用一个值转换器来解决问题。 - biju
2
同时请注意,这适用于TextBlock但不适用于Label。 - Shackles
2
@Shackles StringFormat仅在Binding的目标是String类型的属性时使用。Label.Content是Object类型,因此被忽略。TextBlock.Text是String类型,所以被使用。 - 15ee8f99-57ff-4f92-890c-b56153

20

对于多绑定,需要注意自 .NET 4 版本起的变化。

以下是简短的概述,已在 .NET 4.6 上测试:

常规绑定:

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

多绑定:

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

或者您可以在多绑定中使用 " 代替 '

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

注意:在MultiBinding中使用StringFormat="{}{0:hh\:\:mm\:ss} -> {1:hh\:mm\:ss}"无法工作,这会导致结果为空。


13

我知道这个问题现在已经很老了,但我很惊讶没有人建议这个简单的StringFormat,它可以直接用于TimeSpan

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

2
很多人对此感到困惑。似乎在.NET 4中语法发生了变化。 - McGarnagle

12

1
实际上在 .NET 4-4.5 中有效。此线程中没有其他解决方案可行。 - erodewald
也许在2012年2月这是正确的,但现在不再是了。 - Sheridan

6

毫秒的TimeSpan StringFormat:

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

1
我的解决方案如下:

将元素0复制所需的次数即可。

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接