【问题标题】:Change WPF Calendar control day name format更改 WPF 日历控件日期名称格式
【发布时间】:2013-10-15 09:06:30
【问题描述】:

我目前正在使用 WPF 日历控件。日期名称显示为 Su、Mo、Tu 等。但我希望这些名称显示为 Sun、Mon、Tue 等。我发现没有数据模板属性可以实现这一点。

任何建议将不胜感激。

谢谢

【问题讨论】:

    标签: wpf calendar string-formatting


    【解决方案1】:

    最后,我用下面的转换器解决了,

    public class CalendarDayNameConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            var daynames = CultureInfo.CurrentCulture.DateTimeFormat.DayNames;
            string dayname = value.ToString();
    
            return daynames.First(t => t.StartsWith(dayname)).Substring(0, 3);
        }
    
        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
    

    【讨论】:

    • 你是如何使用转换器的?我也想像你一样格式化日期名称。
    【解决方案2】:

    我对此进行了调查,但不幸的是,我认为您无法实现您想要的。

    首先,我发现 StringFormat 在 MSDN 的 Custom Date and Time Format Strings 页面中显示三个字符的日期名称:

    StringFormat=ddd
    

    然后我想您可能会在 Custom date format for WPF Calendar CalendarItems 帖子中找到解决其余问题的方法。因此,根据@Quartermeister 的想法,我可以尝试以下方法:

    <Calendar>
        <Calendar.CalendarButtonStyle>
            <Style TargetType="primitives:CalendarButton">
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="primitives:CalendarButton">
                            <primitives:CalendarButton>
                                <TextBlock Text="{Binding Day, StringFormat=ddd}"/>
                            </primitives:CalendarButton>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
        </Calendar.CalendarButtonStyle>
    </Calendar>
    

    正如你所想,我离题很远,因为这回答了一个不同的问题。于是我又回到 MSDN 找了the default ControlTemplate for the Calendar control 做进一步的实验。如果您查看ControlTemplate,您将看到一个名为CalendarItemStyleStyle

    其中StyleControlTemplate,在其Resources 部分中,您将看到带有{x:Static CalendarItem.DayTitleTemplateResourceKey} 键的DataTemplate。最后,在DataTemplate 中,您将看到负责显示日期名称的TextBlock

    <TextBlock Foreground="#FF333333"
                       FontWeight="Bold"
                       FontSize="9.5"
                       FontFamily="Verdana"
                       Margin="0,6,0,6"
                       Text="{Binding}"
                       HorizontalAlignment="Center"
                       VerticalAlignment="Center" />
    

    我增加了日期名称的大小,因此我们可以确定这是正确的TextBlock。 (忽略顶部奇怪的Buttons - 他们就是这样,因为我没有复制他们的ControlTemplates):

    现在,如果您查看TextBlock 中的Binding,您会发现不幸的是,它被设置为{Binding}。这意味着它使用整个数据绑定值,而不是在 DateTime 对象上设置特定的 StringFormat。这意味着我们不能使用StringFormat,因为数据绑定值已经是string

    【讨论】:

    • 谢谢谢里迪安。但这太可怕了。
    • 虽然微软对这部分控件的处理方式确实很糟糕,但我猜他们认为我们在那个空间中最多只能容纳两个字母,如果这是真的那么他们 确实有一点。
    • “该空间中的两个字母”对于默认模板可能没问题。但是如果有人要自定义模板,那就不好了。
    • 我完全同意...我只是在寻找他们可能这样做的一些合乎逻辑的理由。
    【解决方案3】:

    我也调查过了。

    我见过的唯一解决方案是使用自定义本地化字典本地化日历,但不幸的是没有提供我们可以使用的键。

    反编译我发现的日历控件,日历控件使用本机函数(nativeGetCalendarData())来本地化日历,所以我将无法轻松检索这些键:(

    【讨论】:

      【解决方案4】:

      请参阅此网站nullskull.com。可下载源包含日期名称转换器和描述

      【讨论】:

        【解决方案5】:

        在这里聚会迟到了,但我想出了一个稍微不同的解决方案,希望它能在国际上更可靠地工作。这是一个两部分的事情。首先,为上面@Sheridan 提到的日期名称制作一个模板:

        <DataTemplate x:Key="{x:Static CalendarItem.DayTitleTemplateResourceKey}">
            <TextBlock>
                <TextBlock.Text>
                    <MultiBinding Converter="{StaticResource CalendarDayNameConverter}">
                        <Binding Path="(Grid.Column)" RelativeSource="{RelativeSource Self}" Mode="OneWay"/>
                        <Binding Path="FirstDayOfWeek" RelativeSource="{RelativeSource AncestorType={x:Type Calendar}}" Mode="OneWay"/>
                    </MultiBinding>
                </TextBlock.Text>
            </TextBlock>
        </DataTemplate>
        

        当然,请根据您的要求对其进行格式化。这里的技巧是Text 绑定到Grid.Column 而不是通常的数据上下文值(WPF 提供的两个字母的日期名称)。网格列号由内部WPF logic设置,应该是可靠的。我们必须使用IMultiValueConverter,因为我们也依赖父级Calendar 控件的FirstDayOfWeek 值:

        public sealed class CalendarDayNameConverter : IMultiValueConverter
        {
            /// <inheritdoc/>
            public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
            {
                if (values?.Length > 0 && values[0] is int index)
                {
                    var dayNames = culture?.DateTimeFormat?.AbbreviatedDayNames;
                    if (dayNames?.Length > 0)
                    {
                        var firstDayOfWeek = values.Length > 1 && values[1] is DayOfWeek d ? d : culture.DateTimeFormat.FirstDayOfWeek;
                        return dayNames[(index + (int)firstDayOfWeek) % dayNames.Length];
                    }
                }
        
                return DependencyProperty.UnsetValue;
            }
        
            /// <inheritdoc/>
            public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) =>
                null;
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2015-02-03
          • 2014-06-05
          • 2020-01-03
          • 2019-04-09
          • 1970-01-01
          • 1970-01-01
          • 2021-08-11
          相关资源
          最近更新 更多