wpf timePicker 時間選擇控件

wpf裏有日期選擇控件,但沒有時間選擇控件。其餘地方也有相似的,但效果並不太好,並且複雜。因此就本身寫了個。參考codeproject上的。html

分兩部分。app

第一部分是.cs文件。也就是control控件的內部邏輯。定義相關屬性,以及委託。主要是經過自定義屬性以及各個屬性(時分秒)之間的聯繫來進行綁定的。代碼以下:ide

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代碼以下:this

<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>

 

這樣就能用了。spa

調用的時候能夠寫個測試程序:code

前臺xaml:xml

<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文件:htm

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));
        }

   
    }
}

 

是否是很簡單呢?blog

效果以下:

 源碼地址: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

感謝每一位閱讀此篇博客的人,但願能夠幫助到你。

相關文章
相關標籤/搜索