代码之家  ›  专栏  ›  技术社区  ›  Amer Farooq

Datepicker格式设置为UK格式(如果已为UK)

  •  3
  • Amer Farooq  · 技术社区  · 6 年前

    在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项本身如下所示

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

    如果我从弹出式日历中选择一个日期,则该日期显示良好。 然而,如果我输入日期,它似乎假设我输入的是美国格式并转换为英国格式。

    i、 e.如果我想像2018年6月5日那样键入2018年6月5日,单击字段后,它会突然变为2018年5月6日。

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

    2 回复  |  直到 6 年前
        1
  •  2
  •   Visual Vincent    6 年前

    看起来 StringFormat 不影响从用户输入接收的值。

    从…起 docs :

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

    我相信有更可靠的解决方案,但我没有找到任何不使用转换器就能解决此问题的方法。

    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'}"
    
        2
  •  1
  •   mm8    6 年前

    您可以创建自定义 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));
            }
        }
    }