首页 > 代码库 > wpf timePicker 时间选择控件

wpf timePicker 时间选择控件

wpf里有日期选择控件,但没有时间选择控件。其他地方也有类似的,但效果并不太好,而且复杂。所以就自己写了个。参考codeproject上的。

分两部分。

第一部分是.cs文件。也就是control控件的内部逻辑。定义相关属性,以及委托。代码如下:

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Windows;using System.Windows.Controls;using System.Windows.Data;using System.Windows.Documents;using System.Windows.Input;using System.Windows.Media;using System.Windows.Media.Imaging;using System.Windows.Navigation;using System.Windows.Shapes;namespace CustomControls{    /// <summary>    /// 按照步骤 1a 或 1b 操作,然后执行步骤 2 以在 XAML 文件中使用此自定义控件。    ///    /// 步骤 1a) 在当前项目中存在的 XAML 文件中使用该自定义控件。    /// 将此 XmlNamespace 特性添加到要使用该特性的标记文件的根     /// 元素中:     ///    ///     xmlns:MyNamespace="clr-namespace:时间选择控件"    ///    ///    /// 步骤 1b) 在其他项目中存在的 XAML 文件中使用该自定义控件。    /// 将此 XmlNamespace 特性添加到要使用该特性的标记文件的根     /// 元素中:     ///    ///     xmlns:MyNamespace="clr-namespace:时间选择控件;assembly=时间选择控件"    ///    /// 您还需要添加一个从 XAML 文件所在的项目到此项目的项目引用,    /// 并重新生成以避免编译错误:     ///    ///     在解决方案资源管理器中右击目标项目,然后依次单击    ///     “添加引用”->“项目”->[浏览查找并选择此项目]    ///    ///    /// 步骤 2)    /// 继续操作并在 XAML 文件中使用控件。    ///    ///     <MyNamespace:TimeSpanPicker/>    ///    /// </summary>    public class TimeSpanPicker : Control    {        static TimeSpanPicker()        {            DefaultStyleKeyProperty.OverrideMetadata(typeof(TimeSpanPicker), new FrameworkPropertyMetadata(typeof(TimeSpanPicker)));        }        /// <summary>        /// 时间控制方法,自动计算时间        /// </summary>        /// <param name="e"></param>        protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)        {            base.OnPropertyChanged(e);            if (e.Property == HourProperty)            {                int hour = (int)e.NewValue;                if (hour == 24)                {                    SetValue(HourProperty, 23);                }                else if (hour==-1)                {                    SetValue(HourProperty, 0);                }                SetValue(TimeSpanProperty, new TimeSpan(Hour, Minute, Second));            }            else if (e.Property == MinuteProperty)            {                int minute = (int)e.NewValue;                if (minute == -1)                {                    if (Hour == 0)                    {                        SetValue(MinuteProperty, 0);                    }                    else                    {                        SetValue(MinuteProperty, 59);                        SetValue(HourProperty, Hour - 1);                    }                }                else if (minute == 60)                {                    if (Hour == 24)                    {                        SetValue(MinuteProperty, 59);                    }                    else                    {                        SetValue(MinuteProperty, 0);                        SetValue(HourProperty, Hour + 1);                    }                }                SetValue(TimeSpanProperty, new TimeSpan(Hour, Minute, Second));            }            else if (e.Property == SecondProperty)            {                int second = (int)e.NewValue;                if (second == -1)                {                    if (Minute > 0 || Hour > 0)                    {                        SetValue(SecondProperty, 59);                        SetValue(MinuteProperty, Minute - 1);                    }                    else                    {                        SetValue(SecondProperty, 0);                    }                }                else if (second == 60)                {                    SetValue(SecondProperty, 0);                    SetValue(MinuteProperty, Minute + 1);                }                //设置时间                SetValue(TimeSpanProperty, new TimeSpan(Hour, Minute, Second));            }            else if (e.Property==TimeSpanProperty)            {                TimeSpan ts=(TimeSpan)e.NewValue;                SetValue(SecondProperty, ts.Seconds);
                SetValue(MinuteProperty, ts.Minutes); 
          SetValue(HourProperty, ts.Hours);   } } public TimeSpan TimeSpan { get { return (TimeSpan)GetValue(TimeSpanProperty); } set { SetValue(TimeSpanProperty, value); } } // Using a DependencyProperty as the backing store for TimeSpan. This enables animation, styling, binding, etc... public static readonly DependencyProperty TimeSpanProperty = DependencyProperty.Register("TimeSpan", typeof(TimeSpan), typeof(TimeSpanPicker), new PropertyMetadata(TimeSpan.Zero)); public int Hour { get { return (int)GetValue(HourProperty); } set { SetValue(HourProperty, value); } } // Using a DependencyProperty as the backing store for Hour. This enables animation, styling, binding, etc... public static readonly DependencyProperty HourProperty = DependencyProperty.Register("Hour", typeof(int), typeof(TimeSpanPicker), new PropertyMetadata(0)); public int Minute { get { return (int)GetValue(MinuteProperty); } set { SetValue(MinuteProperty, value); } } // Using a DependencyProperty as the backing store for Minute. This enables animation, styling, binding, etc... public static readonly DependencyProperty MinuteProperty = DependencyProperty.Register("Minute", typeof(int), typeof(TimeSpanPicker), new PropertyMetadata(0)); public int Second { get { return (int)GetValue(SecondProperty); } set { SetValue(SecondProperty, value); } } // Using a DependencyProperty as the backing store for Second. This enables animation, styling, binding, etc... public static readonly DependencyProperty SecondProperty = DependencyProperty.Register("Second", typeof(int), typeof(TimeSpanPicker), new PropertyMetadata(0)); } }

 

另外,有时候时间选择控件的前台是不希望让用户输入字符及符号的。只能让用户输入int型的时分秒。所以定义了一个numbericTextbox。也就是只能输入数字的文本框。代码如下:

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Text.RegularExpressions;using System.Windows;using System.Windows.Controls;using System.Windows.Input;namespace CustomControls{    public class NumbiricTextBox : TextBox    {        private static Regex regex = new Regex("[0-9]+");        public NumbiricTextBox()        {            SetValue(InputMethod.IsInputMethodEnabledProperty, false);//禁用输入法            DataObject.AddPastingHandler(this, TextBoxPasting);//粘贴时候判断            this.MaxLength = 2;//设置长度,避免过多输入        }        /// <summary>        /// 输入判定,只能输入数字 大于0        /// </summary>        /// <param name="e"></param>        protected override void OnPreviewTextInput(TextCompositionEventArgs e)        {            e.Handled = !regex.IsMatch(e.Text);        }         /// <summary>        /// 滚轮改变值大小        /// </summary>        /// <param name="e"></param>        protected override void OnPreviewMouseWheel(MouseWheelEventArgs e)        {            base.OnPreviewMouseWheel(e);                     var x =   e.Source;           if (x!=null&&x is NumbiricTextBox)           {               NumbiricTextBox tbx = x as NumbiricTextBox;                if (e.Delta > 0)               {                   tbx.Text = (int.Parse(tbx.Text) + 1).ToString();               }               else               {                   tbx.Text = (int.Parse(tbx.Text) - 1).ToString();               }           }        }        //保证值不为空····························        protected override void OnLostFocus(RoutedEventArgs e)        {            base.OnLostFocus(e);            if (string.IsNullOrEmpty(this.Text))            {                this.Text = "0";            }        }        /// <summary>        /// 粘贴事件检查        /// </summary>        /// <param name="sender"></param>        /// <param name="e"></param>        private void TextBoxPasting(object sender, DataObjectPastingEventArgs e)        {            if (e.DataObject.GetDataPresent(typeof(String)))            {                String text = (String)e.DataObject.GetData(typeof(String));                if (!regex.IsMatch(text))                {                    e.CancelCommand();                }            }            else            {                e.CancelCommand();            }        }            }}

 

我们定义了控件,但还是不能用的,必须给控件模板才能 用。控件模板就是根据需要来自定义样式了。我做了个简单的。xaml代码如下:

<ResourceDictionary    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"    xmlns:local="clr-namespace:CustomControls">    <!--<local:Hour2StringConverter x:Key="HourConverter"/>-->    <Style TargetType="{x:Type local:TimeSpanPicker}">        <Setter Property="Template">            <Setter.Value>                <ControlTemplate TargetType="{x:Type local:TimeSpanPicker}">                    <Border Background="{TemplateBinding Background}"                            BorderBrush="{TemplateBinding BorderBrush}"                            BorderThickness="{TemplateBinding BorderThickness}">                        <StackPanel Orientation="Horizontal">                            <local:NumbiricTextBox x:Name="hourTbx" MinWidth="20"  Text="{Binding Path=Hour, RelativeSource={RelativeSource TemplatedParent},UpdateSourceTrigger=PropertyChanged}"  VerticalAlignment="Center" Height="Auto" >                            </local:NumbiricTextBox>                            <Label Content=":" VerticalAlignment="Center" Height="Auto"/>                            <local:NumbiricTextBox  MinWidth="20" Text="{Binding Path=Minute,RelativeSource={RelativeSource TemplatedParent},UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Center" Height="Auto"></local:NumbiricTextBox>                            <Label Content=":" VerticalAlignment="Center" Height="Auto"/>                            <local:NumbiricTextBox  MinWidth="20" Text="{Binding Path=Second,RelativeSource={RelativeSource TemplatedParent},UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Center" Height="Auto"></local:NumbiricTextBox>                        </StackPanel>                    </Border>                </ControlTemplate>            </Setter.Value>        </Setter>    </Style></ResourceDictionary>

 

这样就能用了。

调用的时候可以写个测试程序:

前台xaml:

<Window        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"        xmlns:local="clr-namespace:CustomControls" x:Class="CustomControls.MainWindow"        Title="MainWindow" Height="350" Width="525">    <Grid>        <local:NumbiricTextBox HorizontalAlignment="Left" Margin="74,183,0,0" TextWrapping="Wrap"  VerticalAlignment="Top" Height="69" Width="257" />        <local:TimeSpanPicker HorizontalAlignment="Left" Margin="62,69,0,0" VerticalAlignment="Top" Height="28" Width="180" x:Name="timePicker"  />        <Button Content="获取时间" HorizontalAlignment="Left" Margin="62,117,0,0" VerticalAlignment="Top" Width="75" Click="Button_Click"/>        <Label x:Name="lb1" Content="Label" HorizontalAlignment="Left" Margin="164,117,0,0" VerticalAlignment="Top"/>        <Button Content="设置时间" HorizontalAlignment="Left" Margin="51,32,0,0" VerticalAlignment="Top" Width="75" Click="Button_Click_1"/>    </Grid></Window>

 

后台cs文件:

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Windows;using System.Windows.Controls;using System.Windows.Data;using System.Windows.Documents;using System.Windows.Input;using System.Windows.Media;using System.Windows.Media.Imaging;using System.Windows.Navigation;using System.Windows.Shapes;namespace CustomControls{    /// <summary>    /// MainWindow.xaml 的交互逻辑    /// </summary>    public partial class MainWindow : Window    {        public MainWindow()        {            InitializeComponent();        }        private void Button_Click(object sender, RoutedEventArgs e)        {            lb1.Content = timePicker.TimeSpan.ToString();        }        private void Button_Click_1(object sender, RoutedEventArgs e)        {            timePicker.SetValue(TimeSpanPicker.TimeSpanProperty, new TimeSpan(DateTime.Now.Hour,DateTime.Now.Minute,DateTime.Now.Second));        }       }}

 

是不是很简单呢?

效果如下:

技术分享

 

感谢每一位阅读此篇博客的人,希望可以帮助到你。

 

wpf timePicker 时间选择控件