日期选择器格式设置为英国格式(当已经是英国时)



在 WPF 中,我有一个具有以下文本样式的日期选择器:

<Style TargetType="{x:Type DatePickerTextBox}">
    <Setter Property="Control.Template">
        <Setter.Value>
            <ControlTemplate>
                <TextBox x:Name="PART_TextBox"
                Text="{Binding Path=SelectedDate, StringFormat='dd/MM/yyyy', 
                  RelativeSource={RelativeSource AncestorType={x:Type DatePicker}}}"
                         Foreground="white"/>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

日期选取器项本身如下所示

<DatePicker x:Name="datepickShowDate" Grid.Column="1" Foreground="white" CalendarStyle="{StaticResource styleCalendar}" 
    FontSize="14" HorizontalAlignment="Left" Height="30" 
    VerticalAlignment="Top" Width="139"/>

如果我从弹出日历中选择一个日期,那么日期显示正常。 但是,如果我输入日期,它似乎假设我以美国格式输入并转换为英国格式。

即,如果我想输入5th June 2018,例如05/06/2018,单击该字段时,它突然变为06/05/2018。

我的问题是,有没有办法定义输入格式,而不仅仅是日期选择后日期应该是什么样子?

似乎StringFormat不会影响从用户输入接收的值。

从文档中:

获取或设置一个字符串,该字符串指定如何设置绑定的格式(如果 将绑定值显示为字符串。

我相信有更强大的解决方案,但我没有找到任何可以在不使用转换器的情况下解决这个问题的东西。

public class DateTimeConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        var dateTime = (DateTime?)value;
        if (!dateTime.HasValue)
        {
            return string.Empty;
        }
        var format = (string)parameter;
        return dateTime.Value.ToString(format, culture);
    }
    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        var format = (string)parameter;
        DateTime dateTime;
        if (DateTime.TryParseExact((string)value, format, culture, DateTimeStyles.None, out dateTime))
        {
            return dateTime;
        }
        return DependencyProperty.UnsetValue;
    }
}

这里的诀窍是在 ConvertBack 方法中使用DateTime.TryParseExact,将格式作为参数传递。

但是有一个缺点 - 您只能使用一种格式 - dd/MM/yyyy。如果您输入类似 2018-04-29 的内容 - 它将不起作用。

为了使用此转换器,您需要在资源中声明它:

<local:DateTimeConverter x:Key="converter"/>

并使用ConverterParameter代替StringFormat(虽然您可以使用StringFormat,它将在应用转换器后使用(:

Text="{Binding Path=SelectedDate, 
      RelativeSource={RelativeSource AncestorType={x:Type DatePicker}},
      Converter={StaticResource converter}, 
      ConverterParameter='dd/MM/yyyy'}"

您可以创建自定义DatePicker

public class UkDatePicker : DatePicker
{
    private DatePickerTextBox _datePickerTextBox;
    private const string _shortDatePattern = "dd/MM/yyyy";
    private readonly CultureInfo _formatProvider = new CultureInfo("en-GB");
    public UkDatePicker()
    {
        Language = XmlLanguage.GetLanguage(_formatProvider.IetfLanguageTag);
    }
    public override void OnApplyTemplate()
    {
        base.OnApplyTemplate();
        _datePickerTextBox = Template.FindName("PART_TextBox", this) as DatePickerTextBox;
        if (_datePickerTextBox != null)
        {
            _datePickerTextBox.SetBinding(TextBox.TextProperty, new Binding(nameof(DatePicker.SelectedDate))
            {
                RelativeSource = new RelativeSource() { AncestorType = typeof(DatePicker) },
                StringFormat = _shortDatePattern
            });
            _datePickerTextBox.TextChanged += dptb_TextChanged;
        }
    }
    private void dptb_TextChanged(object sender, TextChangedEventArgs e)
    {
        DateTime dt;
        if (DateTime.TryParseExact(_datePickerTextBox.Text, _shortDatePattern, _formatProvider,
            DateTimeStyles.None, out dt))
        {
            SelectedDate = dt;
        }
    }
}

示例 XAML:

<local:UkDatePicker DockPanel.Dock="Top" SelectedDate="{Binding Date}"/>
<StackPanel Orientation="Horizontal" Margin="0 10 0 0">
    <TextBlock Text="Selected Date: " FontSize="16" FontWeight="Bold"/>
    <TextBlock Text="{Binding Date, StringFormat=dd/MM/yyyy}" FontSize="16"/>
</StackPanel>

查看模型:

public class ViewModel : INotifyPropertyChanged
{
    private DateTime? _date;
    public DateTime? Date
    {
        get { return _date; }
        set { _date = value; NotifyPropertyChanged(); }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

最新更新