zoukankan      html  css  js  c++  java
  • wpf timePicker 时间选择控件

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

    分两部分。

    第一部分是.cs文件。也就是control控件的内部逻辑。定义相关属性,以及委托。主要是通过自定义属性以及各个属性(时分秒)之间的联系来进行绑定的。代码如下:

    using System;
    using System.Windows;
    using System.Windows.Controls;
    
    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);
                    }
                    //else
                    SetValue(TimeSpanProperty, new TimeSpan(Hour, TimeSpan.Minutes, TimeSpan.Seconds));
                }
                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);
                        }
                    }
                    //else
                    SetValue(TimeSpanProperty, new TimeSpan(TimeSpan.Hours, Minute, TimeSpan.Seconds));
                }
                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(TimeSpan.Hours, TimeSpan.Minutes, Second));
                }
                else if (e.Property == TimeSpanProperty)
                {
                    TimeSpan ts = (TimeSpan)e.NewValue;
    
                    SetValue(HourProperty, ts.Hours);
                    SetValue(MinuteProperty, ts.Minutes);
                    SetValue(SecondProperty, ts.Seconds);
                }
            }
    
    
    
            public bool IsReadOnly
            {
                get { return (bool)GetValue(IsReadOnlyProperty); }
                set { SetValue(IsReadOnlyProperty, value); }
            }
    
            // Using a DependencyProperty as the backing store for IsReadOnly.  This enables animation, styling, binding, etc...
            public static readonly DependencyProperty IsReadOnlyProperty =
                DependencyProperty.Register("IsReadOnly", typeof(bool), typeof(TimeSpanPicker), new PropertyMetadata(false));
    
    
    
            public TimeSpan TimeSpan
            {
                get { return (TimeSpan)GetValue(TimeSpanProperty); }
                set { SetValue(TimeSpanProperty, value); }
            }
    
    
            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); }
            }
    
    
            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); }
            }
    
    
            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); }
            }
    
    
            public static readonly DependencyProperty SecondProperty =
                DependencyProperty.Register("Second", typeof(int), typeof(TimeSpanPicker), new PropertyMetadata(0));
    
        }
    }
    

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

    using System;
    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);
                if (!regex.IsMatch(this.Text))
                {
                    return;
                }
                e.Handled = !regex.IsMatch(this.Text);
                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.IsNullOrWhiteSpace(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));
            }
    
       
        }
    }
    

    是不是很简单呢?

    效果如下:

     源码地址:http://files.cnblogs.com/files/lizhijian/%E6%97%B6%E9%97%B4%E9%80%89%E6%8B%A9%E6%8E%A7%E4%BB%B6.rar

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

  • 相关阅读:
    【NOIP2013】货车运输 最大生成树+LCA
    【NOIP2017】逛公园 拆点最短路+拓扑(记忆化搜索
    【NOIP2016】愤怒的小鸟 搜索
    洛谷9月月赛II 赛后瞎写
    java基础--第八天
    java基础--第七天
    Java基础--第六天
    Java基础--第五天
    Java基础---第四天
    Java基础--第三天
  • 原文地址:https://www.cnblogs.com/congqiandehoulai/p/5823948.html
Copyright © 2011-2022 走看看