wpf timePicker 时间选择控件

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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 时间选择控件的主要内容,如果未能解决你的问题,请参考以下文章

安卓学习笔记Android Studio第8课——TimePicker和DatePicker

一起Talk Android吧(第四百四十五回:UI控件之TimePicker)

WPF实用小工具

wpf 控件四周扩散颜色

使用NumberPicker定制自己喜欢的Date&TimePicker

wpf 如何创建时间控件(时分秒)