• WPF DatePicker只显示年和月 修改:可以只显示年


    最近的项目,查询时只需要年和月,不需要日,因此需要对原有的DatePicker进行修改,查询了网上的内容,最终从一篇帖子里看到了添加附加属性的方法,地址是http://stackoverflow.com/questions/1798513/wpf-toolkit-datepicker-month-year-only

    原文是用了两个类,其中一个是为了让DatePicker下的Calendar只显示年月,不显示日,另一个类是为了让DatePicker格式化为yyyy-MM格式,但是从文章中可以看出,有人提出了,用格式化类进行格式化时,DatePicker控件会闪动一下,当然不影响使用。如果不想使用文章中提到的类进行格式化,也可以用我上一篇文章中的方法进行格式化,不会出现闪动的情况。

    只显示年月的类(2016-12-20修改,可以只显示年)

    public class DatePickerCalendar
        {
    
            public static bool GetIsYear(DependencyObject obj)
            {
                return (bool)obj.GetValue(IsYearProperty);
            }
    
            public static void SetIsYear(DependencyObject obj, bool value)
            {
                obj.SetValue(IsYearProperty, value);
            }
    
            // Using a DependencyProperty as the backing store for IsYear.  This enables animation, styling, binding, etc...
            public static readonly DependencyProperty IsYearProperty =
                DependencyProperty.RegisterAttached("IsYear", typeof(bool), typeof(DatePickerCalendar), new PropertyMetadata(false, new PropertyChangedCallback(OnIsMonthYearChanged)));
    
    
    
            public static readonly DependencyProperty IsMonthYearProperty =
            DependencyProperty.RegisterAttached("IsMonthYear", typeof(bool), typeof(DatePickerCalendar),
                                                new PropertyMetadata(OnIsMonthYearChanged));
    
            public static bool GetIsMonthYear(DependencyObject dobj)
            {
                return (bool)dobj.GetValue(IsMonthYearProperty);
            }
    
            public static void SetIsMonthYear(DependencyObject dobj, bool value)
            {
                dobj.SetValue(IsMonthYearProperty, value);
            }
    
            private static void OnIsMonthYearChanged(DependencyObject dobj, DependencyPropertyChangedEventArgs e)
            {
                var datePicker = (DatePicker)dobj;
    
                Application.Current.Dispatcher
                    .BeginInvoke(DispatcherPriority.Loaded,
                                 new Action<DatePicker, DependencyPropertyChangedEventArgs>(SetCalendarEventHandlers),
                                 datePicker, e);
            }
    
            private static void SetCalendarEventHandlers(DatePicker datePicker, DependencyPropertyChangedEventArgs e)
            {
                if (e.NewValue == e.OldValue)
                    return;
    
                if ((bool)e.NewValue)
                {
                    datePicker.CalendarOpened += DatePickerOnCalendarOpened;
                    datePicker.CalendarClosed += DatePickerOnCalendarClosed;
                }
                else
                {
                    datePicker.CalendarOpened -= DatePickerOnCalendarOpened;
                    datePicker.CalendarClosed -= DatePickerOnCalendarClosed;
                }
            }
    
            private static void DatePickerOnCalendarOpened(object sender, RoutedEventArgs routedEventArgs)
            {
                var calendar = GetDatePickerCalendar(sender);
                if (GetIsYear(sender as DatePicker))
                {
                    calendar.DisplayMode = CalendarMode.Decade;
                }
                else
                {
                    calendar.DisplayMode = CalendarMode.Year;
                }
    
                calendar.DisplayModeChanged += CalendarOnDisplayModeChanged;
            }
    
            private static void DatePickerOnCalendarClosed(object sender, RoutedEventArgs routedEventArgs)
            {
                var datePicker = (DatePicker)sender;
                var calendar = GetDatePickerCalendar(sender);
                datePicker.SelectedDate = calendar.SelectedDate;
    
                calendar.DisplayModeChanged -= CalendarOnDisplayModeChanged;
            }
    
            private static void CalendarOnDisplayModeChanged(object sender, CalendarModeChangedEventArgs e)
            {
                var calendar = (Calendar)sender;
                var datePicker = GetCalendarsDatePicker(calendar);
    
                bool mode = (GetIsYear(datePicker) && calendar.DisplayMode != CalendarMode.Year) || (GetIsMonthYear(datePicker) && calendar.DisplayMode != CalendarMode.Month);
    
                if (mode)
                    return;
    
                calendar.SelectedDate = GetSelectedCalendarDate(calendar.DisplayDate);
    
                datePicker.IsDropDownOpen = false;
            }
    
            private static Calendar GetDatePickerCalendar(object sender)
            {
                var datePicker = (DatePicker)sender;
                var popup = (Popup)datePicker.Template.FindName("PART_Popup", datePicker);
                return ((Calendar)popup.Child);
            }
    
            private static DatePicker GetCalendarsDatePicker(FrameworkElement child)
            {
                var parent = (FrameworkElement)child.Parent;
                if (parent.Name == "PART_Root")
                    return (DatePicker)parent.TemplatedParent;
                return GetCalendarsDatePicker(parent);
            }
    
            private static DateTime? GetSelectedCalendarDate(DateTime? selectedDate)
            {
                if (!selectedDate.HasValue)
                    return null;
                return new DateTime(selectedDate.Value.Year, selectedDate.Value.Month, 1);
            }
        }
    DatePickerCalendar

    调用方式

    <DatePicker Width="200" Height="30" local:DatePickerCalendar.IsMonthYear="True"/>

    展示效果

    从图上就能看到左右不一样,左侧的是添加附加属性的,点击以后直接显示月,后侧没用的则显示到日,虽然都格式化为了yyyy-MM,但是Calendar如果显示到日的话,用户体验不好。

    ========================================================================================================================

    2015年8月4日 记:

    今天在项目中发现一个问题,就是采用我上一篇帖子中的三句话进行DatePicker时间的格式化显示,但是由于用的是Thread,所以是在线程里进行格式化的,因此,影响到了同事做的其他模块,因为大部分都是格式化为yyyy-MM-dd,但是由于我的一个页面是格式化为了yyyy-MM,而其中的一个同事并没有在他的构造函数里使用三句格式化他的DatePicker,从而导致他其他的时间计算出现问题,因此在保证原有功能不变的情况下,需要显示yyyy-MM,就需要用到原帖子中的另一个类。

    DatePickerDateFormat

    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;
                }
            }
        }
    DatePickerDateFormat

    总的调用方法 

    <DatePicker conver:DatePickerCalendar.IsMonthYear="True" conver:DatePickerDateFormat.DateFormat="yyyy-MM" />

     ========================================================================================================================

    2016年12月20日

    修改原来的代码,增加IsYear附加属性,用法和IsMonthYear一样,设置为True则只显示年份

  • 相关阅读:
    计算机基础知识
    看 C++ Primer 的58页, 讲拷贝时不能忽略 底层const这里的说的原因有点牵强, 这里给出自己的理解
    GitHub
    让 typora和word一样好用
    推荐几款好用的文本编辑器,让您的办公更方便快捷。
    UML类图几种关系的总结
    poll, ppoll
    信号之sigaction函数
    posix多线程有感--自旋锁
    Linux IPC
  • 原文地址:https://www.cnblogs.com/ZXdeveloper/p/4665772.html
Copyright © 2020-2023  润新知