WPF 可选择年月及显示格式的DatePicker控件

来源:互联网 发布:opencv 求矩阵平均值 编辑:程序博客网 时间:2024/05/29 04:06

转载于 http://www.cnblogs.com/ZXdeveloper/archive/2015/07/21/4665772.html

代码部分:

public class XDatePicker : DatePicker    {        static XDatePicker()        {            DefaultStyleKeyProperty.OverrideMetadata(typeof(XDatePicker), new FrameworkPropertyMetadata(typeof(XDatePicker)));        }        #region 属性        static bool IsMonthYear, IsYear;        #region IsMonthYear        public static bool GetIsMonthYear(DependencyObject dobj)        {            return (bool)dobj.GetValue(IsMonthYearProperty);        }        public static void SetIsMonthYear(DependencyObject dobj, bool value)        {            dobj.SetValue(IsMonthYearProperty, value);        }        public static readonly DependencyProperty IsMonthYearProperty = DependencyProperty.RegisterAttached("IsMonthYear", typeof(bool), typeof(XDatePicker), new PropertyMetadata(OnIsMonthYearChanged));        private static void OnIsMonthYearChanged(DependencyObject dobj, DependencyPropertyChangedEventArgs e)        {            var datePicker = (XDatePicker)dobj;            IsMonthYear = GetIsMonthYear(dobj);            Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Loaded, new Action<XDatePicker, DependencyPropertyChangedEventArgs>(SetCalendarEventHandlers), datePicker, e);        }        #endregion        #region IsYear        public static bool GetIsYear(DependencyObject dobj)        {            return (bool)dobj.GetValue(IsYearProperty);        }        public static void SetIsYear(DependencyObject dobj, bool value)        {            dobj.SetValue(IsYearProperty, value);        }        public static readonly DependencyProperty IsYearProperty = DependencyProperty.RegisterAttached("IsYear", typeof(bool), typeof(XDatePicker), new PropertyMetadata(OnIsYearChanged));        private static void OnIsYearChanged(DependencyObject dobj, DependencyPropertyChangedEventArgs e)        {            var datePicker = (XDatePicker)dobj;            IsYear = GetIsYear(dobj);            Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Loaded, new Action<XDatePicker, DependencyPropertyChangedEventArgs>(SetCalendarEventHandlers), datePicker, e);        }        #endregion        #region DateFormat        public static string GetDateFormat(DependencyObject dobj)        {            return (string)dobj.GetValue(DateFormatProperty);        }        public static void SetDateFormat(DependencyObject dobj, string value)        {            dobj.SetValue(DateFormatProperty, value);        }        public static readonly DependencyProperty DateFormatProperty = DependencyProperty.RegisterAttached("DateFormat", typeof(string), typeof(XDatePicker), new PropertyMetadata(OnDateFormatChanged));        private static void OnDateFormatChanged(DependencyObject dobj, DependencyPropertyChangedEventArgs e)        {            var datePicker = (XDatePicker)dobj;            Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Loaded, new Action<XDatePicker>(ApplyDateFormat), datePicker);        }        private static void ApplyDateFormat(XDatePicker datePicker)        {            var binding = new Binding("SelectedDate")            {                RelativeSource = new RelativeSource { AncestorType = typeof(XDatePicker) },                Converter = new DatePickerDateTimeConverter(),                ConverterParameter = new Tuple<XDatePicker, 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;            e.Handled = true;            var textBox = (TextBox)sender;            var datePicker = (XDatePicker)textBox.TemplatedParent;            var dateStr = textBox.Text;            var formatStr = GetDateFormat(datePicker);            datePicker.SelectedDate = DatePickerDateTimeConverter.StringToDateTime(datePicker, formatStr, dateStr);        }        private class DatePickerDateTimeConverter : IValueConverter        {            public object Convert(object value, Type targetType, object parameter, CultureInfo culture)            {                var formatStr = ((Tuple<XDatePicker, 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<XDatePicker, 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(XDatePicker 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;            }        }        #endregion        private static void SetCalendarEventHandlers(XDatePicker 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 (IsMonthYear) calendar.DisplayMode = CalendarMode.Year;            if (IsYear) calendar.DisplayMode = CalendarMode.Decade;            var datePicker = (XDatePicker)sender;            var textBox = GetTemplateTextBox(datePicker);            var formatStr = GetDateFormat(datePicker);            textBox.Text = DatePickerDateTimeConverter.DateTimeToString(formatStr, datePicker.SelectedDate);            calendar.DisplayModeChanged += CalendarOnDisplayModeChanged;        }        private static void DatePickerOnCalendarClosed(object sender, RoutedEventArgs routedEventArgs)        {            var datePicker = (XDatePicker)sender;            var calendar = GetDatePickerCalendar(sender);            datePicker.SelectedDate = calendar.SelectedDate;            calendar.DisplayModeChanged -= CalendarOnDisplayModeChanged;        }        private static void CalendarOnDisplayModeChanged(object sender, CalendarModeChangedEventArgs e)        {            var calendar = (System.Windows.Controls.Calendar)sender;            if (IsMonthYear && calendar.DisplayMode != CalendarMode.Month)                return;            if (IsYear && calendar.DisplayMode != CalendarMode.Year)                return;            calendar.SelectedDate = GetSelectedCalendarDate(calendar.DisplayDate);            var datePicker = GetCalendarsDatePicker(calendar);            datePicker.IsDropDownOpen = false;        }        private static System.Windows.Controls.Calendar GetDatePickerCalendar(object sender)        {            var datePicker = (XDatePicker)sender;            var popup = (Popup)datePicker.Template.FindName("PART_Popup", datePicker);            return ((System.Windows.Controls.Calendar)popup.Child);        }        private static XDatePicker GetCalendarsDatePicker(FrameworkElement child)        {            var parent = (FrameworkElement)child.Parent;            if (parent.Name == "PART_Root") return (XDatePicker)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);        }        #endregion    }

样式部分:

    <Style TargetType="{x:Type local:XDatePicker}">        <Setter Property="Height" Value="28"/>        <Setter Property="Width" Value="100"/>        <Setter Property="Margin" Value="5,0"/>        <Setter Property="BorderBrush" Value="gray"/>        <Setter Property="BorderThickness" Value="1"/>        <Setter Property="SelectedDateFormat" Value="Short"/>        <Setter Property="Template">            <Setter.Value>                <ControlTemplate TargetType="{x:Type local:XDatePicker}">                    <Border CornerRadius="3" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}">                        <VisualStateManager.VisualStateGroups>                            <VisualStateGroup x:Name="CommonStates">                                <VisualState x:Name="Normal"/>                                <VisualState x:Name="Disabled">                                    <Storyboard>                                        <DoubleAnimation Duration="0" To="1" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="PART_Popup"/>                                    </Storyboard>                                </VisualState>                            </VisualStateGroup>                        </VisualStateManager.VisualStateGroups>                        <DockPanel x:Name="PART_Root">                            <DockPanel.Resources>                                <ControlTemplate x:Key="DropDownButtonTemplate" TargetType="{x:Type Button}">                                    <Border Height="18" Width="18">                                        <Path x:Name="calendar" Fill="#FF368DC0" RenderTransformOrigin="0.5,0.5" Stretch="Fill"<span style="white-space:pre">                                          </span>  Data="F1 M 18.0025,57.0081L 18.0025,23.0032L 23.0032,23.0032L 23.0032,20.0028C 23.0033,18.898 23.8988,18.0025 25.0035,18.0025L 29.004,18.0025C 30.1087,18.0025 31.0042,18.898 31.0043,20.0026L 31.0043,23.0032L 45.0063,23.0032L 45.0062,20.0026C 45.0062,18.8978 45.9018,18.0023 47.0065,18.0023L 51.0071,18.0023C 52.1118,18.0023 53.0074,18.8978 53.0074,20.0026L 53.0074,23.0032L 58.0081,23.0032L 58.0081,57.0081L 18.0025,57.0081 Z M 20,54L 56,54L 56,28L 20,28L 20,54 Z M 23,44L 31,44L 31,52L 23,52L 23,44 Z M 34,44L 42,44L 42,52L 34,52L 34,44 Z M 45,44L 53,44L 53,52L 45,52L 45,44 Z M 23,32L 31,32L 31,40L 23,40L 23,32 Z M 34,32L 42,32L 42,40L 34,40L 34,32 Z M 45,32L 53,32L 53,40L 45,40L 45,32 Z M 48.5067,20.0029C 47.6782,20.0029 47.0065,20.6745 47.0065,21.5031L 47.0065,24.5035C 47.0065,25.332 47.6782,26.0037 48.5067,26.0037L 49.5068,26.0037C 50.3354,26.0037 51.0071,25.332 51.0071,24.5035L 51.0071,21.5031C 51.0071,20.6745 50.3354,20.0029 49.5068,20.0029L 48.5067,20.0029 Z M 26.5037,20.0028C 25.6751,20.0028 25.0035,20.6745 25.0035,21.503L 25.0035,24.5035C 25.0035,25.332 25.6751,26.0037 26.5037,26.0037L 27.5038,26.0037C 28.3324,26.0037 29.004,25.332 29.004,24.5035L 29.004,21.503C 29.004,20.6745 28.3324,20.0028 27.5038,20.0028L 26.5037,20.0028 Z "/>                                    </Border>                                    <ControlTemplate.Triggers>                                        <Trigger Property="IsMouseOver" Value="true">                                            <Setter TargetName="calendar" Property="Fill" Value="#1BBBFA"/>                                        </Trigger>                                    </ControlTemplate.Triggers>                                </ControlTemplate>                            </DockPanel.Resources>                            <Button x:Name="PART_Button" DockPanel.Dock="Right" Foreground="{TemplateBinding Foreground}" Focusable="False" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="3,0" Template="{StaticResource DropDownButtonTemplate}" Width="20"/>                            <Grid Margin="3,0,0,0">                                <DatePickerTextBox x:Name="PART_TextBox" Focusable="{TemplateBinding Focusable}" VerticalAlignment="Stretch" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Center"/>                                <Popup x:Name="PART_Popup" IsHitTestVisible="False" Opacity="0" AllowsTransparency="True" Placement="Bottom" PlacementTarget="{Binding ElementName=PART_TextBox}" StaysOpen="False"/>                            </Grid>                        </DockPanel>                    </Border>                    <ControlTemplate.Triggers>                        <DataTrigger Binding="{Binding Source={x:Static SystemParameters.HighContrast}}" Value="false">                            <Setter Property="Foreground" TargetName="PART_TextBox" Value="{Binding Foreground, RelativeSource={RelativeSource TemplatedParent}}"/>                        </DataTrigger>                    </ControlTemplate.Triggers>                </ControlTemplate>            </Setter.Value>        </Setter>    </Style>
0 0