【问题标题】:How to change format (e.g. dd/MMM/yyyy) of DateTimePicker in WPF application如何在 WPF 应用程序中更改 DateTimePicker 的格式(例如 dd/MMM/yyyy)
【发布时间】:2009-03-13 05:29:33
【问题描述】:

我想在 WPF 应用程序中更改 DateTimePicker 中选择的日期格式

【问题讨论】:

    标签: .net wpf datetime datetimepicker datetime-format


    【解决方案1】:

    我最近正在处理这个问题。我找到了一种执行这种自定义格式的简单方法,希望对您有所帮助。您需要做的第一件事是在您的 XAML 中将特定样式应用于您当前的 DatePicker,就像这样:

    <DatePicker.Resources>
        <Style TargetType="{x:Type DatePickerTextBox}">
            <Setter Property="Control.Template">
                <Setter.Value>
                    <ControlTemplate>
                        <TextBox x:Name="PART_TextBox" Width="113" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch" Text="{Binding Path=SelectedDate,Converter={StaticResource DateTimeFormatter},RelativeSource={RelativeSource AncestorType={x:Type DatePicker}},ConverterParameter=dd-MMM-yyyy}" BorderBrush="{DynamicResource BaseBorderBrush}" />
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </DatePicker.Resources>
    

    正如您在本部分中所注意到的,当时存在一个名为 DateTimeFormatter 的转换器,用于绑定到“PART_TextBox”的 Text 属性。此转换器接收包含您的自定义格式的转换器参数。最后我们在 C# 中为 DateTimeFormatter 转换器添加代码。

    public class DateTimeConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            DateTime? selectedDate = value as DateTime?;
    
            if (selectedDate != null)
            {
                string dateTimeFormat = parameter as string;
                return selectedDate.Value.ToString(dateTimeFormat);
            }
    
            return "Select Date";
        }
    
        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            try
            {
    
                var valor = value as string;
                if (!string.IsNullOrEmpty(valor))
                {
                    var retorno = DateTime.Parse(valor);
                    return retorno;
                }
    
                return null;
            }
            catch
            {
                return DependencyProperty.UnsetValue;
            }
        }
    }
    

    我希望这对您有所帮助。如有任何问题或改进建议,请告诉我。

    【讨论】:

      【解决方案2】:
      Thread.CurrentThread.CurrentCulture = (CultureInfo)Thread.CurrentThread.CurrentCulture.Clone();
      Thread.CurrentThread.CurrentCulture.DateTimeFormat.ShortDatePattern = "dd-MMM-yyyy";      
      

      【讨论】:

      • 这在 UI 控件中发生了变化,但在 viewmodel 属性中没有。我得到相同格式的计算机日期格式。请问有什么想法吗?
      • 这正是我所需要的。谢谢!
      【解决方案3】:

      将此样式添加到您的 xaml 或 App.xaml 文件中

       <Style TargetType="{x:Type DatePickerTextBox}">
           <Setter Property="VerticalContentAlignment" Value="Center"/>
           <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}}}" />
                   </ControlTemplate>
               </Setter.Value>
           </Setter>
       </Style>
      

      【讨论】:

        【解决方案4】:

        在 XAML 中:

        <toolkit:DatePicker SelectedDateFormat="Long" />
        

        或

        <toolkit:DatePicker SelectedDateFormat="Short" />
        

        【讨论】:

        • +1 我想知道是否有办法在 XAML 中提供自定义日期时间格式字符串。
        • 原题中的DatePickerTextBox控件没有这个属性。
        【解决方案5】:

        感谢@Fernando García 提供的基础。

        我已经为 DatePicker 编写了一个 DateFormat 附加属性,它可以让您提供一个用于显示和输入的格式字符串。

        对于输入,它将尝试使用提供的格式进行解析,然后尝试使用当前区域性的格式进行解析。

        问题格式的用法示例:

        <DatePicker my:DatePickerDateFormat.DateFormat="dd/MMM/yyyy"/>
        

        DateFormat 附加属性是:

        public class DatePickerDateFormat
        {
            public static readonly DependencyProperty DateFormatProperty =
                DependencyProperty.RegisterAttached("DateFormat", typeof (string), typeof (DatePickerDateFormat),
                                                    new PropertyMetadata(OnDateFormatChanged));
        
            public static string GetDateFormat(DependencyObject dobj)
            {
                return (string) dobj.GetValue(DateFormatProperty);
            }
        
            public static void SetDateFormat(DependencyObject dobj, string value)
            {
                dobj.SetValue(DateFormatProperty, value);
            }
        
            private static void OnDateFormatChanged(DependencyObject dobj, DependencyPropertyChangedEventArgs e)
            {
                var datePicker = (DatePicker) dobj;
        
                Application.Current.Dispatcher.BeginInvoke(
                    DispatcherPriority.Loaded, new Action<DatePicker>(ApplyDateFormat), datePicker);
            }
        
            private static void ApplyDateFormat(DatePicker datePicker)
            {
                var binding = new Binding("SelectedDate")
                    {
                        RelativeSource = new RelativeSource {AncestorType = typeof (DatePicker)},
                        Converter = new DatePickerDateTimeConverter(),
                        ConverterParameter = new Tuple<DatePicker, string>(datePicker, GetDateFormat(datePicker))
                    };
                var textBox = GetTemplateTextBox(datePicker);
                textBox.SetBinding(TextBox.TextProperty, binding);
        
                textBox.PreviewKeyDown -= TextBoxOnPreviewKeyDown;
                textBox.PreviewKeyDown += TextBoxOnPreviewKeyDown;
        
                datePicker.CalendarOpened -= DatePickerOnCalendarOpened;
                datePicker.CalendarOpened += DatePickerOnCalendarOpened;
            }
        
            private static TextBox GetTemplateTextBox(Control control)
            {
                control.ApplyTemplate();
                return (TextBox) control.Template.FindName("PART_TextBox", control);
            }
        
            private static void TextBoxOnPreviewKeyDown(object sender, KeyEventArgs e)
            {
                if (e.Key != Key.Return)
                    return;
        
                /* DatePicker subscribes to its TextBox's KeyDown event to set its SelectedDate if Key.Return was
                 * pressed. When this happens its text will be the result of its internal date parsing until it
                 * loses focus or another date is selected. A workaround is to stop the KeyDown event bubbling up
                 * and handling setting the DatePicker.SelectedDate. */
        
                e.Handled = true;
        
                var textBox = (TextBox) sender;
                var datePicker = (DatePicker) textBox.TemplatedParent;
                var dateStr = textBox.Text;
                var formatStr = GetDateFormat(datePicker);
                datePicker.SelectedDate = DatePickerDateTimeConverter.StringToDateTime(datePicker, formatStr, dateStr);
            }
        
            private static void DatePickerOnCalendarOpened(object sender, RoutedEventArgs e)
            {
                /* When DatePicker's TextBox is not focused and its Calendar is opened by clicking its calendar button
                 * its text will be the result of its internal date parsing until its TextBox is focused and another
                 * date is selected. A workaround is to set this string when it is opened. */
        
                var datePicker = (DatePicker) sender;
                var textBox = GetTemplateTextBox(datePicker);
                var formatStr = GetDateFormat(datePicker);
                textBox.Text = DatePickerDateTimeConverter.DateTimeToString(formatStr, datePicker.SelectedDate);
            }
        
            private class DatePickerDateTimeConverter : IValueConverter
            {
                public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
                {
                    var formatStr = ((Tuple<DatePicker, string>) parameter).Item2;
                    var selectedDate = (DateTime?) value;
                    return DateTimeToString(formatStr, selectedDate);
                }
        
                public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
                {
                    var tupleParam = ((Tuple<DatePicker, string>) parameter);
                    var dateStr = (string) value;
                    return StringToDateTime(tupleParam.Item1, tupleParam.Item2, dateStr);
                }
        
                public static string DateTimeToString(string formatStr, DateTime? selectedDate)
                {
                    return selectedDate.HasValue ? selectedDate.Value.ToString(formatStr) : null;
                }
        
                public static DateTime? StringToDateTime(DatePicker datePicker, string formatStr, string dateStr)
                {
                    DateTime date;
                    var canParse = DateTime.TryParseExact(dateStr, formatStr, CultureInfo.CurrentCulture,
                                                          DateTimeStyles.None, out date);
        
                    if (!canParse)
                        canParse = DateTime.TryParse(dateStr, CultureInfo.CurrentCulture, DateTimeStyles.None, out date);
        
                    return canParse ? date : datePicker.SelectedDate;
                }
            }
        }
        

        【讨论】:

        • 我尝试使用上述类来获取正确的日期格式。乍一看,我认为它按预期工作。但过了一会儿,我发现当我选择一个日期时,我会以正确的格式得到那个日期。例如dd.MM.yyyy。然后,当我将焦点移到其他控件上时,我看到日期再次转换为默认格式,即 MM.dd.yyyy。由此我观察到 DateSeparator 仍然是指定的,但是一旦 DatePicker 失去焦点,日期的格式就会改变。
        【解决方案6】:
        DatePicker1.SelectedDate = DatePicker1.SelectedDate.Value.ToString("dd/MM/yyyy")
        

        【讨论】:

        • 这还能编译吗?
        【解决方案7】:

        通常日期时间格式存储在资源文件中,因为这将有助于应用程序的国际化。

        您可以从资源文件中选择格式并使用ToString(DATE_FORMAT)

        在您的情况下,您可能想要使用

        dateTimePicker.SelectedDate.ToString("dd-MMM-yyyy");
        

        【讨论】:

          【解决方案8】:

          对我来说,改变环境以改变DatePicker 格式(如Thread.CurrentCulture)不是一个好主意。 当然,您可以创建从DatePicker 派生的Control 并实现像Format 这样的依赖属性,但这需要花费太多精力。

          我发现的简单而优雅的解决方案是不将值绑定到 SelectedDate 本身,而是绑定到一些未使用的属性(我为此使用了 ToolTip 属性)并在 SelectedDate 更改时更新此属性。

          单向绑定的 C# 实现如下所示:

              DatePicker datePicker = new DatePicker();
              datePicker.SetBinding(ToolTipProperty, "Date");
              datePicker.SelectedDateChanged += (s, ea) =>
                  {
                      DateTime? date = datePicker.SelectedDate;
                      string value = date != null ? date.Value.ToString("yyyy-MM-dd") : null;
                      datePicker.ToolTip = value;
                  };
          

          XAML+C# 应该如下所示:

          XAML:

          <DatePicker ToolTip="{Binding Date Mode=TwoWay}"
                      SelectedDateChanged="DatePicker_SelectedDateChanged"/>
          

          C#:

          private void DatePicker_SelectedDateChanged(object sender, EventArgs ea)
          {
              DatePicker datePicker = (DatePicker)sender;
              DateTime? date = datePicker.SelectedDate;
              string value = date != null ? date.Value.ToString("yyyy-MM-dd") : null;
              datePicker.ToolTip = value;
          }
          

          对于双向实现处理ToolTipChanged事件的方式相同,更新SelectedDate。

          【讨论】:

            【解决方案9】:

            试试这个

                private void UserControl_Loaded(object sender, RoutedEventArgs e)
                {
                  DateLabel.Content = Convert.ToDateTime(datePicker1.Text).ToString("dd-MM-yyyy");
                }
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2020-04-06
              • 1970-01-01
              • 1970-01-01
              • 2018-04-30
              • 2018-04-11
              相关资源
              最近更新 更多