Silverlight 学习——重写DatePicker (二)

本文介绍了如何修复Silverlight DatePicker在只读模式下仍可删除的BUG,通过设置TextBox的IsReadOnly属性实现真正的只读。同时提出新的需求,即根据DateMode属性控制用户仅选择年或月,利用DatePicker内置的Calendar控件,并通过扩展方法查找并修改Calendar。文章提供了相关代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、问题与修改

            在上一篇文章中,出现了一个BUG,设置DatePicer控件输入只读,并非是真真的只读,仍可以进行删除,这与只读的概念相违背了,利用TextBox的IsReadOnly属性可以实现这一要求,不需要自己去定义只读!

二、新的需求

             在很多需求中,只需要选择年,或者是只需要选择月。在界面中,很多程序往往只使用ComboBox来实现这一需求。但是DatePicker完全能够实现,大家都知道DatePicer控件使用了一个隐藏的 Calendar控件!手动更改CalendarMode属性完全可以实现!因此,在DatePicker控件中,添加属性DateMode属性,继承自CalendarMode,通过改变DateMode属性来实现效果!

            同时,要用到扩展方法(在本例中方法名:public static IEnumerable<DependencyObject> Descendents(this DependencyObject root)){})!它是一个静态类中的一个静态方法,通过此方法在DependencyObject类型中添加Descendents。在本例中的目的是为了找到Calendar控件!具体如何使用,请查找相关的资料了!吐舌头

二、代码

    public static class ControlsHelper
    {
        /// <summary>
        /// 扩展DependencyObject Descendents方法,递归找到制定的控件
        /// </summary>
        /// <param name="root"></param>
        /// <returns></returns>
        public static IEnumerable<DependencyObject> Descendents(this DependencyObject root)
        {
            int count = VisualTreeHelper.GetChildrenCount(root);
            for (int i = 0; i < count; i++)
            {
                var child = VisualTreeHelper.GetChild(root, i);
                yield return child;
                foreach (var descendent in Descendents(child))
                    yield return descendent;
            }
        }
    }

    public class DatePickerEx : DatePicker
    {

        #region 私有字段
        DatePickerTextBox CurrentTextBox;//DatePicker的文本框控件
        Popup CurrentPopup;//DatePicker控件的TempPart
        Calendar CurrentCalendar;//日历控件
        Button CurrentButon;//DatePicker的Button控件
        string DateFormat;//定义时间显示格式
        string _InputText;

        public static readonly DependencyProperty IsReadOnlyProperty = DependencyProperty.Register("IsReadOnly", typeof(bool), typeof(DatePickerEx), new PropertyMetadata(false));
        //public static readonly DependencyProperty InputTextProperty = DependencyProperty.Register("InputText", typeof(String), typeof(DatePickerEx), new PropertyMetadata("", InputTextChanged));
        public static readonly DependencyProperty DateModeProperty = DependencyProperty.Register("DateMode", typeof(CalendarMode), typeof(DatePickerEx), new PropertyMetadata(CalendarMode.Month, DateModeChanged));
        #endregion

        #region 属性
        /// <summary>
        /// 得到手动输入的值
        /// </summary>
        public string InputText
        {
            //get { return (string)GetValue(InputTextProperty); }
            //set { SetValue(InputTextProperty, value); }
            get { return _InputText == null ? "" : _InputText; }
            private set { _InputText = value; }
        }
        /// <summary>
        /// 启用和关闭手动输入
        /// </summary>
        public bool IsReadOnly
        {
            get { return (bool)GetValue(IsReadOnlyProperty); }
            set { SetValue(IsReadOnlyProperty, value); }
        }
        ///// <summary>
        /// 输入时间类型
        /// </summary>
        public CalendarMode DateMode
        {
            get { return (CalendarMode)GetValue(DateModeProperty); }
            set { SetValue(DateModeProperty, value); }
        }
        #endregion

        #region 重写方法及事件
        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
            this.CurrentTextBox = GetTemplateChild("TextBox") as DatePickerTextBox;
            this.CurrentPopup = GetTemplateChild("Popup") as Popup;
            this.CurrentButon = GetTemplateChild("Button") as Button;

            #region 注册及绑定事件
            if (null != this.CurrentTextBox)
            {
                //this.CurrentTextBox.BorderThickness = new Thickness(1);
                //this.CurrentButon.Margin = new Thickness(-25, 0, 0, 0);
                this.SetTextMode(this.CurrentTextBox);
                this.CurrentTextBox.IsReadOnly = this.IsReadOnly;
                this.CurrentTextBox.TextChanged += ((sender, e) =>
                {
                    if (this.IsReadOnly)
                        this.CurrentTextBox.Text = this.SelectedDate.HasValue ? this.SelectedDate.Value.ToString(this.DateFormat) : "";
                    else
                    {
                        if (this.CurrentTextBox.Text.Trim().Length >= this.DateFormat.Length)
                        {
                            DateTime timeTemp;
                            if (DateTime.TryParse(this.CurrentTextBox.Text.Trim(), out timeTemp))
                                this.CurrentTextBox.Text = timeTemp.ToString(this.DateFormat);
                        }
                        this.InputText = this.CurrentTextBox.Text;
                    }
                    SetTextMode(this.CurrentTextBox);
                });

            }

            this.CalendarClosed += new RoutedEventHandler(DatePickerEx_CalendarClosed);


            if (this.DateMode == CalendarMode.Month)
                return;

            if (null != this.CurrentPopup)
                //利用扩展方法找到Calendar控件
                this.CurrentCalendar = this.CurrentPopup.Child.Descendents().OfType<Calendar>().FirstOrDefault();


            if (null != this.CurrentButon)
                this.CurrentButon.Click += ((sender, e) =>
                {
                    this.CurrentPopup.IsOpen = true;
                });


            if (null != this.CurrentCalendar)
            {

                this.CurrentCalendar.IsTodayHighlighted = true;
                this.CurrentCalendar.DisplayModeChanged += new
                    EventHandler<CalendarModeChangedEventArgs>(CurrentCalendar_DisplayModeChanged);
                this.CurrentCalendar.DisplayMode = this.DateMode;
                this.CurrentCalendar.LostMouseCapture += ((sender, e) =>
                {
                    this.SelectedDate = this.DisplayDate;
                });

            }
            #endregion
        }

        void CurrentCalendar_DisplayModeChanged(object sender, CalendarModeChangedEventArgs e)
        {
            this.CurrentCalendar.DisplayModeChanged -= CurrentCalendar_DisplayModeChanged;
            this.CurrentCalendar.DisplayModeChanged += CurrentCalendar_DisplayModeChanged;
            Calendar cal = (Calendar)sender;

            //首次加载以及重新赋值DisplayMode  Calendar视图情况判断
            if (e.OldMode.Equals(CalendarMode.Year) && !e.NewMode.Equals(CalendarMode.Month))
                cal.DisplayMode = e.NewMode;
            else
                cal.DisplayMode = this.DateMode;


            //仅选择月 Calendar关闭情况判断
            if (e.NewMode.Equals(CalendarMode.Month))
                this.CurrentPopup.IsOpen = false;


            //只选择年。 Calendar 关闭情况判断
            if (this.DateMode == CalendarMode.Decade && e.NewMode == CalendarMode.Year && e.OldMode == this.DateMode)
                this.CurrentPopup.IsOpen = false;
        }
        /// <summary>
        /// 设置日期显示格式
        /// </summary>
        /// <param name="tbx"></param>
        protected void SetTextMode(DatePickerTextBox tbx)
        {
            if (null == tbx)
                return;
            switch (this.DateMode)
            {
                case CalendarMode.Year:
                    DateFormat = "yyyy-MM";
                    tbx.Watermark = "<yyyy-MM>";
                    break;
                case CalendarMode.Decade:
                    DateFormat = "yyyy";
                    tbx.Watermark = "<yyyy>";
                    break;
                default:
                    DateFormat = "yyyy-MM-dd";
                    break;
            }
            tbx.UpdateLayout();
        }
        #endregion


        //protected override 
        #region 自定义事件
        protected override void OnKeyUp(KeyEventArgs e)
        {
            base.OnKeyUp(e);
            if (!this.IsReadOnly)
                this.InputText = this.CurrentTextBox.Text;
        }
        protected virtual void DatePickerEx_CalendarClosed(object sender, RoutedEventArgs e)
        {
            if (null != this.SelectedDate)
                this.Text = this.SelectedDate.Value.ToString(this.DateFormat);
            this.InputText = this.Text;
        }
        //protected static void InputTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        //{
        //    DatePickerEx sender = d as DatePickerEx;
        //    if (null != sender.CurrentTextBox)
        //        sender.CurrentTextBox.Text = e.NewValue.ToString();
        //}
        protected static void DateModeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            DatePickerEx sender = d as DatePickerEx;
            if (null != sender.CurrentCalendar)
                sender.CurrentCalendar.DisplayMode = (CalendarMode)e.NewValue;
            sender.SetTextMode(sender.CurrentTextBox);
        }
        #endregion
    }


 

评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值