Как изменить формат (например, dd / MMM / yyyy) DateTimePicker в приложении WPF

Я хочу изменить формат даты, выбранный в DateTimePicker в приложении WPF


person Community    schedule 13.03.2009    source источник


Ответы (9)


Я постоянно занимался этим вопросом. Я нашел простой способ выполнить этот пользовательский формат и надеюсь, что он вам поможет. Первое, что вам нужно сделать, это применить определенный стиль к вашему текущему DatePicker точно так же, в вашем XAML:

<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 для привязки к свойству Text элемента «PART_TextBox». Этот конвертер получает параметр конвертера, который включает ваш собственный формат. Наконец, мы добавляем код на 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;
        }
    }
}

Надеюсь, это поможет вам. Пожалуйста, дайте мне знать о любых проблемах или предложениях по улучшению.

person Fernando García    schedule 09.12.2010

Добавьте этот стиль в свой файл 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>
person Hallgeir Engen    schedule 05.04.2016

В XAML:

<toolkit:DatePicker SelectedDateFormat="Long" />

or

<toolkit:DatePicker SelectedDateFormat="Short" />
person Stuart    schedule 10.11.2009
comment
+1 Интересно, есть ли способ предоставить строку пользовательского формата даты и времени в XAML. - person Doguhan Uluca; 01.07.2011
comment
Это свойство недоступно для элемента управления DatePickerTextBox в исходном вопросе. - person Wouter; 13.09.2011

Спасибо @Fernando García за основу.

Я написал присоединенное свойство DateFormat для DatePicker, которое позволяет вам предоставить строку формата для отображения и ввода.

Для ввода он попытается выполнить синтаксический анализ, используя предоставленный формат, возвращаясь к попыткам синтаксического анализа с использованием текущего формата языка и региональных параметров.

Пример использования с форматом вопроса:

<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;
        }
    }
}
person Simon Brydon    schedule 20.10.2012
comment
Я попытался использовать вышеупомянутый класс, чтобы получить правильный формат даты. На первый взгляд я подумал, что он работает, как и ожидалось. Но через некоторое время я обнаружил, что когда я выбираю дату, я получаю ее в правильном формате. Например, дд.ММ.гггг. Затем, когда я переместил фокус на другой элемент управления, я увидел, что дата снова преобразуется в формат по умолчанию, то есть MM.dd.yyyy. Из этого я заметил, что DateSeparator остается указанным, но формат даты меняется, как только DatePicker теряет фокус. - person Vishal; 31.08.2014

Обычно формат даты и времени хранится в файле ресурсов, потому что это поможет в интернационализации приложения.

Вы можете выбрать формат из файла ресурсов и использовать ToString(DATE_FORMAT)

В вашем случае вы можете использовать

dateTimePicker.SelectedDate.ToString("dd-MMM-yyyy");
person abhilash    schedule 13.03.2009

На мой взгляд, изменение среды для изменения формата DatePicker (например, Thread.CurrentCulture) - не лучшая идея. Конечно, вы можете создать Control, производный от DatePicker, и реализовать свойство зависимостей, например 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.

person Vitaliy Ulantikov    schedule 11.11.2011

Попробуй это

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

person    schedule
comment
это изменяется в элементе управления пользовательского интерфейса, но не в свойстве viewmodel. Я получаю тот же формат компьютерной даты. любая идея, пожалуйста? - person J R B; 06.03.2014
comment
Это именно то, что мне нужно. Спасибо! - person BlueDev; 02.11.2019

person    schedule
comment
Это вообще компилируется? - person code4life; 20.06.2015