以下控件采用https://www.cnblogs.com/cssmystyle/archive/2011/01/17/1937361.html部分代码
以下控件采用https://www.cnblogs.com/xiaomingg/p/11180355.html部分代码
TimeSpanBox 效果如下,用于选择时间的长度,年最大值99,月最大值11,日最大值30,时最大值23,分最大值59,秒最大值59
第一步,新建WPF用户TimepanBox
<UserControl x:Class="WPFApp.Controls.TimeSpanBox.TimeSpanBox" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:local="clr-namespace:WPFApp.Controls.TimeSpanBox" BorderBrush="Gray" BorderThickness="1" mc:Ignorable="d" Focusable="False" d:DesignHeight="25" d:DesignWidth="200"> <UserControl.Resources> <ControlTemplate x:Key="UPBtnTemplate" TargetType="{x:Type RepeatButton}"> <Border BorderThickness="0"> <Border.Background> <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0" Opacity="1"> <GradientStop Color="#FFF9FAFB" Offset="0" /> <GradientStop Color="#FFC4CCD4" Offset="0.973" /> </LinearGradientBrush> </Border.Background> <ContentPresenter HorizontalAlignment="Center" Content="{TemplateBinding Button.Content}" VerticalAlignment="Center"/> </Border> <ControlTemplate.Triggers> <Trigger Property="IsPressed" Value="True"> <Setter Property="RenderTransform"> <Setter.Value> <TranslateTransform X=".5" Y=".3"/> </Setter.Value> </Setter> </Trigger> </ControlTemplate.Triggers> </ControlTemplate> <ControlTemplate x:Key="DownBtnTemplate" TargetType="{x:Type RepeatButton}"> <Border BorderThickness="0"> <Border.Background> <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0" Opacity="1"> <GradientStop Color="#FFC4CCD4" Offset="0.973" /> <GradientStop Color="#FFF9FAFB" Offset="0" /> </LinearGradientBrush> </Border.Background> <ContentPresenter HorizontalAlignment="Center" Content="{TemplateBinding Button.Content}" VerticalAlignment="Center"/> </Border> <ControlTemplate.Triggers> <Trigger Property="IsPressed" Value="True"> <Setter Property="RenderTransform"> <Setter.Value> <TranslateTransform X=".5" Y=".3"/> </Setter.Value> </Setter> </Trigger> </ControlTemplate.Triggers> </ControlTemplate> </UserControl.Resources> <Grid Background="White"> <Grid.ColumnDefinitions> <ColumnDefinition/> <ColumnDefinition Width="auto"/> <ColumnDefinition/> <ColumnDefinition Width="auto"/> <ColumnDefinition/> <ColumnDefinition Width="auto"/> <ColumnDefinition/> <ColumnDefinition Width="auto"/> <ColumnDefinition/> <ColumnDefinition Width="auto"/> <ColumnDefinition/> <ColumnDefinition Width="auto"/> <ColumnDefinition Width="auto"/> </Grid.ColumnDefinitions> <TextBox Grid.Column="0" BorderBrush="Transparent" BorderThickness="0" x:Name="txtYear" VerticalContentAlignment="Center" InputMethod.IsInputMethodEnabled="False" TextAlignment="Right" Padding="0,0,1,0"/> <TextBlock Text="年" Grid.Column="1" VerticalAlignment="Center" x:Name="txtbYear"/> <TextBox Grid.Column="2" BorderBrush="Transparent" BorderThickness="0" x:Name="txtMonth" VerticalContentAlignment="Center" InputMethod.IsInputMethodEnabled="False" TextAlignment="Right" Padding="0,0,1,0"/> <TextBlock Text="月" Grid.Column="3" VerticalAlignment="Center" x:Name="txtbMonth"/> <TextBox Grid.Column="4" BorderBrush="Transparent" BorderThickness="0" x:Name="txtDay" VerticalContentAlignment="Center" InputMethod.IsInputMethodEnabled="False" TextAlignment="Right" Padding="0,0,1,0"/> <TextBlock Text="天" Grid.Column="5" VerticalAlignment="Center" x:Name="txtbDay"/> <TextBox Grid.Column="6" BorderBrush="Transparent" BorderThickness="0" x:Name="txtHour" VerticalContentAlignment="Center" InputMethod.IsInputMethodEnabled="False" TextAlignment="Right" Padding="0,0,1,0"/> <TextBlock Text="时" Grid.Column="7" VerticalAlignment="Center" x:Name="txtbHour"/> <TextBox Grid.Column="8" BorderBrush="Transparent" BorderThickness="0" x:Name="txtMinute" VerticalContentAlignment="Center" InputMethod.IsInputMethodEnabled="False" TextAlignment="Right" Padding="0,0,1,0"/> <TextBlock Text="分" Grid.Column="9" VerticalAlignment="Center" x:Name="txtbMinute"/> <TextBox Grid.Column="10" BorderBrush="Transparent" BorderThickness="0" x:Name="txtSecound" VerticalContentAlignment="Center" InputMethod.IsInputMethodEnabled="False" TextAlignment="Right" Padding="0,0,1,0"/> <TextBlock Text="秒" Grid.Column="11" VerticalAlignment="Center" x:Name="txtbSecound"/> <UniformGrid Grid.Column="12" Rows="2" x:Name="gridShow" Margin="1,0,0,0"> <RepeatButton Padding="0" Width="{Binding RelativeSource={RelativeSource Mode=Self},Path=ActualHeight}" Focusable="False" VerticalContentAlignment="Center" Template="{StaticResource UPBtnTemplate}" Command="{x:Static local:TimeSpanBox.IncreaseCommand}"> <Path Height="6" Width="12" Stretch="Fill" Opacity="1" Fill="#FF554646" Data="M 666.5,597 C666.5,597 678.5,597 678.5,597 678.5,597 672.5,591 672.5,591 672.5,591 666.5,597 666.5,597 z"/> </RepeatButton> <RepeatButton Padding="0" Width="{Binding RelativeSource={RelativeSource Mode=Self},Path=ActualHeight}" Focusable="False" VerticalContentAlignment="Center" Template="{StaticResource DownBtnTemplate}" Command="{x:Static local:TimeSpanBox.DecreaseCommand}"> <Path Height="6" Width="12" Stretch="Fill" Opacity="1" Fill="#FF554646" Data="M 666.5,609 C666.5,609 678.5,609 678.5,609 678.5,609 672.5,615 672.5,615 672.5,615 666.5,609 666.5,609 z"/> </RepeatButton> </UniformGrid> </Grid> </UserControl>
对应自定义用户控件的后台代码
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 WPFApp.Controls.TimeSpanBox { public partial class TimeSpanBox : UserControl { private TextBox previousFocus = null; public TimeSpanBox() { InitializeComponent(); MouseButtonEventHandler PreviewMouseDown = (o1, e1) => { TextBox textbox = o1 as TextBox; if (textbox != null) { textbox.Focus(); e1.Handled = true; } }; txtYear.PreviewMouseDown += PreviewMouseDown; txtMonth.PreviewMouseDown += PreviewMouseDown; txtDay.PreviewMouseDown += PreviewMouseDown; txtHour.PreviewMouseDown += PreviewMouseDown; txtMinute.PreviewMouseDown += PreviewMouseDown; txtSecound.PreviewMouseDown += PreviewMouseDown; RoutedEventHandler GotFocus = (o1, e1) => { TextBox txt = o1 as TextBox; if (txt != null) { txt.SelectAll(); txt.Background = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#FFBFEDF1")); txt.Foreground = new SolidColorBrush(Colors.Black); txt.PreviewMouseDown -= new MouseButtonEventHandler(PreviewMouseDown); } previousFocus = txt; }; txtYear.GotFocus += GotFocus; txtMonth.GotFocus += GotFocus; txtDay.GotFocus += GotFocus; txtHour.GotFocus += GotFocus; txtMinute.GotFocus += GotFocus; txtSecound.GotFocus += GotFocus; RoutedEventHandler LostFocus = (o1, e1) => { var textBox = o1 as TextBox; if (textBox != null) { textBox.Background = new SolidColorBrush(Colors.Transparent); textBox.Foreground = new SolidColorBrush(Colors.Black); textBox.PreviewMouseDown += new MouseButtonEventHandler(PreviewMouseDown); } }; txtYear.LostFocus += LostFocus; txtMonth.LostFocus += LostFocus; txtDay.LostFocus += LostFocus; txtHour.LostFocus += LostFocus; txtMinute.LostFocus += LostFocus; txtSecound.LostFocus += LostFocus; KeyEventHandler KeyDowm = (o1, e1) => { TextBox txt = o1 as TextBox; if (e1.Key == Key.Enter || (e1.Key == Key.Right && txt.SelectionStart == txt.Text.Length)) { FocusNextText(txt); } else if (((e1.Key == Key.Delete || e1.Key == Key.Back) && (txt.Text == "0" || string.IsNullOrEmpty(txt.Text))) || (txt.SelectionStart == 0 && e1.Key == Key.Left) ) { e1.Handled = true; if (!(txt.SelectionStart == 0 && e1.Key == Key.Left)) txt.Text = "0"; FocusPreviousText(txt); } }; txtYear.PreviewKeyDown += KeyDowm; txtMonth.PreviewKeyDown += KeyDowm; txtDay.PreviewKeyDown += KeyDowm; txtHour.PreviewKeyDown += KeyDowm; txtMinute.PreviewKeyDown += KeyDowm; txtSecound.PreviewKeyDown += KeyDowm; txtYear.TextChanged += TextYear_Changed; txtMonth.TextChanged += txtMonth_Changed; txtDay.TextChanged += txtDay_Changed; txtHour.TextChanged += txtHour_Changed; txtMinute.TextChanged += txtMinute_Changed; txtSecound.TextChanged += txtSecound_Changed; txtbYear.MouseLeftButtonDown += (o1, e1) => { txtYear.Focus(); txtYear.SelectAll(); }; txtbMonth.MouseLeftButtonDown += (o1, e1) => { txtMonth.Focus(); txtMonth.SelectAll(); }; txtbDay.MouseLeftButtonDown += (o1, e1) => { txtDay.Focus(); txtDay.SelectAll(); }; txtbHour.MouseLeftButtonDown += (o1, e1) => { txtHour.Focus(); txtHour.SelectAll(); }; txtbMinute.MouseLeftButtonDown += (o1, e1) => { txtMinute.Focus(); txtMinute.SelectAll(); }; txtbSecound.MouseLeftButtonDown += (o1, e1) => { txtSecound.Focus(); txtSecound.SelectAll(); }; this.SetTextBoxBindingText(this.txtYear, "YearText"); this.SetTextBoxBindingText(this.txtMonth, "MonthText"); this.SetTextBoxBindingText(this.txtDay, "DayText"); this.SetTextBoxBindingText(this.txtHour, "HourText"); this.SetTextBoxBindingText(this.txtMinute, "MinuteText"); this.SetTextBoxBindingText(this.txtSecound, "SecoundText"); } private void SetTextBoxBindingText(TextBox targetTxt,string bindingPath) { Binding binding = new Binding(bindingPath); binding.Source = this; binding.Mode = BindingMode.TwoWay; binding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged; targetTxt.SetBinding(TextBox.TextProperty, binding); } #region 注册路由命令 #region 注册鼠标左键按下事件 static TimeSpanBox() { InitializeCommands(); //EventManager.RegisterClassHandler(typeof(TimeSpanBox), // Mouse.MouseDownEvent, new MouseButtonEventHandler(TimeSpanBox.OnMouseLeftButtonDown), true); } private static void OnMouseLeftButtonDown(object sender, MouseButtonEventArgs e) { TimeSpanBox control = (TimeSpanBox)sender; //如果某人点击控件的部分只,但是该控件没有聚焦, //本空间需要获取焦点来处理正确处理键盘 if (!control.IsKeyboardFocusWithin)//获取一个值,该值指示键盘焦点是否处于元素边界内的任何位置(包括键盘焦点是否位于任何可视子元素的边界内)。 { e.Handled = control.Focus() || e.Handled; } } #endregion private static RoutedCommand m_IncreaseCommand; private static RoutedCommand m_DecreaseCommand; public static RoutedCommand IncreaseCommand { get { return m_IncreaseCommand; } } public static RoutedCommand DecreaseCommand { get { return m_DecreaseCommand; } } private static void InitializeCommands() { m_IncreaseCommand = new RoutedCommand("IncreaseCommand", typeof(TimeSpanBox)); CommandManager.RegisterClassCommandBinding(typeof(TimeSpanBox), new CommandBinding(m_IncreaseCommand, OnIncreaseCommand)); CommandManager.RegisterClassInputBinding(typeof(TimeSpanBox), new InputBinding(m_IncreaseCommand, new KeyGesture(Key.Up))); m_DecreaseCommand = new RoutedCommand("DecreaseCommand", typeof(TimeSpanBox)); CommandManager.RegisterClassCommandBinding(typeof(TimeSpanBox), new CommandBinding(m_DecreaseCommand, OnDecreaseCommand)); CommandManager.RegisterClassInputBinding(typeof(TimeSpanBox), new InputBinding(m_DecreaseCommand, new KeyGesture(Key.Down))); } private static void OnDecreaseCommand(object sender, ExecutedRoutedEventArgs e) { TimeSpanBox control = sender as TimeSpanBox; if (control != null && control.previousFocus != null) { if (control.previousFocus == control.txtYear) { control.Year = Math.Max(0, control.Year - 1); control.txtYear.SelectAll(); } else if (control.previousFocus == control.txtMonth) { control.Month = Math.Max(0, control.Month - 1); control.txtMonth.SelectAll(); } else if (control.previousFocus == control.txtDay) { control.Day = Math.Max(0, control.Day - 1); control.txtDay.SelectAll(); } else if (control.previousFocus == control.txtHour) { control.Hour = Math.Max(0, control.Hour - 1); control.txtHour.SelectAll(); } else if (control.previousFocus == control.txtMinute) { control.Minutes = Math.Max(0, control.Minutes - 1); control.txtMinute.SelectAll(); } else if (control.previousFocus == control.txtSecound) { control.Secound = Math.Max(0, control.Secound - 1); control.txtSecound.SelectAll(); } } } private static void OnIncreaseCommand(object sender, ExecutedRoutedEventArgs e) { TimeSpanBox control = sender as TimeSpanBox; if (control != null) { if (control.previousFocus == control.txtYear) { control.Year = Math.Min(99, control.Year + 1); control.txtYear.SelectAll(); } else if (control.previousFocus == control.txtMonth) { control.Month = Math.Min(11, control.Month + 1); control.txtMonth.SelectAll(); } else if (control.previousFocus == control.txtDay) { control.Day = Math.Min(30, control.Day + 1); control.txtDay.SelectAll(); } else if (control.previousFocus == control.txtHour) { control.Hour = Math.Min(23, control.Hour + 1); control.txtHour.SelectAll(); } else if (control.previousFocus == control.txtMinute) { control.Minutes = Math.Min(59, control.Minutes + 1); control.txtMinute.SelectAll(); } else if (control.previousFocus == control.txtSecound) { control.Secound = Math.Min(59, control.Secound + 1); control.txtSecound.SelectAll(); } } } #endregion #region 跳转到上个文本框 private void FocusNextText(TextBox currTxt) { TextBox[] textboxArray = new TextBox[] { txtYear, txtMonth, txtDay, txtHour, txtMinute, txtSecound }; bool[] isVisibleArray = new bool[] { IsYearVisible, IsMonthVisible, IsDayVisible, IsHourVisible, IsMinuteVisible, IsSecoundVisible }; int index = Array.IndexOf(textboxArray, currTxt); if (index != -1) { var findTxt = textboxArray.Skip(index + 1).FirstOrDefault(txt => isVisibleArray[Array.IndexOf(textboxArray, txt)]); if (findTxt != null) { findTxt.Focus(); } } } #endregion #region 跳转到下个文本框 private void FocusPreviousText(TextBox currTxt) { TextBox[] textboxArray = new TextBox[] { txtYear, txtMonth, txtDay, txtHour, txtMinute, txtSecound }; bool[] isVisibleArray = new bool[] { IsYearVisible, IsMonthVisible, IsDayVisible, IsHourVisible, IsMinuteVisible, IsSecoundVisible }; int index = Array.IndexOf(textboxArray, currTxt); if (index != -1) { var findTxt = textboxArray.Take(index).Reverse().FirstOrDefault(txt => isVisibleArray[Array.IndexOf(textboxArray, txt)]); if (findTxt != null) { findTxt.Focus(); } } } #endregion #region 年份改变 private bool CanRaiseTxtChaned_Year_AttachDP = true; private void TextYear_Changed(object sender, TextChangedEventArgs e) { string year = txtYear.Text; if (string.IsNullOrEmpty(year)) { SetYear(0); if (txtYear.IsFocused == true) txtYear.SelectAll(); } else { int newYear = 0; bool result = int.TryParse(year, out newYear); if (result == true && newYear >= 0 && this.Year != newYear) { if (newYear > 99) { SetText_Year("99"); SetYear(99); txtMonth.Focus(); } else { SetText_Year(newYear.ToString()); SetYear(newYear); } if (txtYear.Text.Length == 2) FocusNextText(txtYear); } else { SetYear(0); SetText_Year("0"); } } } private void SetText_Year(string newValue) { txtYear.TextChanged -= TextYear_Changed; txtYear.Text = newValue; txtYear.TextChanged += TextYear_Changed; } private void SetYear(int year) { CanRaiseTxtChaned_Year_AttachDP = false; this.Year = year; CanRaiseTxtChaned_Year_AttachDP = true; } #endregion #region 月份改变 private bool CanRaiseTxtChaned_Month_AttachDP = true; private void txtMonth_Changed(object sender, TextChangedEventArgs e) { string month = txtMonth.Text; if (string.IsNullOrEmpty(month)) { SetMonth(0); if (txtMonth.IsFocused == true) txtMonth.SelectAll(); } else { int newMonth = 0; bool result = int.TryParse(month, out newMonth); if (result == true && newMonth >= 0 && this.Month != newMonth) { if (newMonth > 11) { SetText_Month("11"); SetMonth(11); txtDay.Focus(); } else { SetText_Month(newMonth.ToString()); SetMonth(newMonth); } if (txtMonth.Text.Length == 2) FocusNextText(txtMonth); } else { SetMonth(0); SetText_Month("0"); } } } private void SetText_Month(string newValue) { txtMonth.TextChanged -= txtMonth_Changed; txtMonth.Text = newValue; txtMonth.TextChanged += txtMonth_Changed; } private void SetMonth(int month) { CanRaiseTxtChaned_Month_AttachDP = false; this.Month = month; CanRaiseTxtChaned_Month_AttachDP = true; } #endregion #region 日改变 private bool CanRaiseTxtChaned_Day_AttachDP = true; private void txtDay_Changed(object sender, TextChangedEventArgs e) { string day = txtDay.Text; if (string.IsNullOrEmpty(day)) { SetDay(0); if (txtDay.IsFocused == true) txtDay.SelectAll(); } else { int newDay = 0; bool result = int.TryParse(day, out newDay); if (result == true && newDay >= 0 && this.Day != newDay) { if (newDay > 30) { SetText_Day("30"); SetDay(30); txtHour.Focus(); } else { SetText_Day(newDay.ToString()); SetDay(newDay); } if (txtDay.Text.Length == 2) FocusNextText(txtDay); } else { SetDay(0); SetText_Day("0"); } } } private void SetText_Day(string newValue) { txtDay.TextChanged -= txtDay_Changed; txtDay.Text = newValue; txtDay.TextChanged += txtDay_Changed; } private void SetDay(int day) { CanRaiseTxtChaned_Day_AttachDP = false; this.Day = day; CanRaiseTxtChaned_Day_AttachDP = true; } #endregion #region 时改变 private bool CanRaiseTxtChaned_Hour_AttachDP = true; private void txtHour_Changed(object sender, TextChangedEventArgs e) { string hour = txtHour.Text; if (string.IsNullOrEmpty(hour)) { SetDay(0); if (txtHour.IsFocused == true) txtHour.SelectAll(); } else { int newHour = 0; bool result = int.TryParse(hour, out newHour); if (result == true && newHour >= 0 && this.Hour != newHour) { if (newHour > 23) { SetText_Hour("23"); SetHour(23); txtMinute.Focus(); } else { SetText_Hour(newHour.ToString()); SetHour(newHour); } if (txtHour.Text.Length == 2) FocusNextText(txtHour); } else { SetHour(0); SetText_Hour("0"); } } } private void SetText_Hour(string newValue) { txtHour.TextChanged -= txtHour_Changed; txtHour.Text = newValue; txtHour.TextChanged += txtHour_Changed; } private void SetHour(int hour) { CanRaiseTxtChaned_Hour_AttachDP = false; this.Hour = hour; CanRaiseTxtChaned_Hour_AttachDP = true; } #endregion #region 分改变 private bool CanRaiseTxtChaned_Minute_AttachDP = true; private void txtMinute_Changed(object sender, TextChangedEventArgs e) { string minute = txtMinute.Text; if (string.IsNullOrEmpty(minute)) { SetMinute(0); if (txtMinute.IsFocused == true) txtMinute.SelectAll(); } else { int newMinute = 0; bool result = int.TryParse(minute, out newMinute); if (result == true && newMinute >= 0 && this.Minutes != newMinute) { if (newMinute > 59) { SetText_Minute("59"); SetMinute(59); txtSecound.Focus(); } else { SetText_Minute(newMinute.ToString()); SetMinute(newMinute); } if (txtMinute.Text.Length == 2) FocusNextText(txtMinute); } else { SetMinute(0); SetText_Minute("0"); } } } private void SetText_Minute(string newValue) { txtMinute.TextChanged -= txtMinute_Changed; txtMinute.Text = newValue; txtMinute.TextChanged += txtMinute_Changed; } private void SetMinute(int Minute) { CanRaiseTxtChaned_Minute_AttachDP = false; this.Minutes = Minute; CanRaiseTxtChaned_Minute_AttachDP = true; } #endregion #region 秒改变 private bool CanRaiseTxtChaned_Secound_AttachDP = true; private void txtSecound_Changed(object sender, TextChangedEventArgs e) { string secound = txtSecound.Text; if (string.IsNullOrEmpty(secound)) { SetSecound(0); if (txtSecound.IsFocused == true) txtSecound.SelectAll(); } else { int newSecound = 0; bool result = int.TryParse(secound, out newSecound); if (result == true && newSecound >= 0 && this.Secound != newSecound) { if (newSecound > 59) { SetText_Secound("59"); SetSecound(59); txtSecound.SelectionStart = txtSecound.Text.Length; } else { SetText_Secound(newSecound.ToString()); SetSecound(newSecound); } } else { SetSecound(0); SetText_Secound("0"); } } } private void SetText_Secound(string newValue) { txtSecound.TextChanged -= txtSecound_Changed; txtSecound.Text = newValue; txtSecound.TextChanged += txtSecound_Changed; } private void SetSecound(int secound) { CanRaiseTxtChaned_Secound_AttachDP = false; this.Secound = secound; CanRaiseTxtChaned_Secound_AttachDP = true; } #endregion #region IsYearVisible public bool IsYearVisible { get { return (bool)GetValue(IsYearVisibleProperty); } set { SetValue(IsYearVisibleProperty, value); } } public static readonly DependencyProperty IsYearVisibleProperty = DependencyProperty.Register("IsYearVisible", typeof(bool), typeof(TimeSpanBox), new PropertyMetadata(true, On_IsYearVisible)); private static void On_IsYearVisible(DependencyObject d, DependencyPropertyChangedEventArgs e) { TimeSpanBox sender = d as TimeSpanBox; if (sender != null) { Grid innerGrid = (Grid)sender.Content; innerGrid.ColumnDefinitions[0].Width = e.NewValue != null && e.NewValue is bool && (bool)e.NewValue == true ? new GridLength(1, GridUnitType.Star) : new GridLength(0); innerGrid.ColumnDefinitions[1].Width = e.NewValue != null && e.NewValue is bool && (bool)e.NewValue == true ? GridLength.Auto : new GridLength(0); if (innerGrid.ColumnDefinitions[0].Width == new GridLength(0)) { sender.SetText_Year("0"); sender.CanRaiseTxtChaned_Year_AttachDP = false; sender.Year = 0; sender.CanRaiseTxtChaned_Year_AttachDP = true; } } } #endregion #region IsMonthVisible public bool IsMonthVisible { get { return (bool)GetValue(IsMonthVisibleProperty); } set { SetValue(IsMonthVisibleProperty, value); } } public static readonly DependencyProperty IsMonthVisibleProperty = DependencyProperty.Register("IsMonthVisible", typeof(bool), typeof(TimeSpanBox), new PropertyMetadata(true, On_IsMonthVisible)); private static void On_IsMonthVisible(DependencyObject d, DependencyPropertyChangedEventArgs e) { TimeSpanBox sender = d as TimeSpanBox; if (sender != null) { Grid innerGrid = (Grid)sender.Content; innerGrid.ColumnDefinitions[2].Width = e.NewValue != null && e.NewValue is bool && (bool)e.NewValue == true ? new GridLength(1, GridUnitType.Star) : new GridLength(0); innerGrid.ColumnDefinitions[3].Width = e.NewValue != null && e.NewValue is bool && (bool)e.NewValue == true ? GridLength.Auto : new GridLength(0); } } #endregion #region IsDayVisible public bool IsDayVisible { get { return (bool)GetValue(IsDayVisibleProperty); } set { SetValue(IsDayVisibleProperty, value); } } public static readonly DependencyProperty IsDayVisibleProperty = DependencyProperty.Register("IsDayVisible", typeof(bool), typeof(TimeSpanBox), new PropertyMetadata(true, On_IsDayVisible)); private static void On_IsDayVisible(DependencyObject d, DependencyPropertyChangedEventArgs e) { TimeSpanBox sender = d as TimeSpanBox; if (sender != null) { Grid innerGrid = (Grid)sender.Content; innerGrid.ColumnDefinitions[4].Width = e.NewValue != null && e.NewValue is bool && (bool)e.NewValue == true ? new GridLength(1, GridUnitType.Star) : new GridLength(0); innerGrid.ColumnDefinitions[5].Width = e.NewValue != null && e.NewValue is bool && (bool)e.NewValue == true ? GridLength.Auto : new GridLength(0); } } #endregion #region IsHourVisible public bool IsHourVisible { get { return (bool)GetValue(IsHourVisibleProperty); } set { SetValue(IsHourVisibleProperty, value); } } public static readonly DependencyProperty IsHourVisibleProperty = DependencyProperty.Register("IsHourVisible", typeof(bool), typeof(TimeSpanBox), new PropertyMetadata(true, On_IsHourVisible)); private static void On_IsHourVisible(DependencyObject d, DependencyPropertyChangedEventArgs e) { TimeSpanBox sender = d as TimeSpanBox; if (sender != null) { Grid innerGrid = (Grid)sender.Content; innerGrid.ColumnDefinitions[6].Width = e.NewValue != null && e.NewValue is bool && (bool)e.NewValue == true ? new GridLength(1, GridUnitType.Star) : new GridLength(0); innerGrid.ColumnDefinitions[7].Width = e.NewValue != null && e.NewValue is bool && (bool)e.NewValue == true ? GridLength.Auto : new GridLength(0); } } #endregion #region IsMinuteVisible public bool IsMinuteVisible { get { return (bool)GetValue(IsMinuteVisibleProperty); } set { SetValue(IsMinuteVisibleProperty, value); } } public static readonly DependencyProperty IsMinuteVisibleProperty = DependencyProperty.Register("IsMinuteVisible", typeof(bool), typeof(TimeSpanBox), new PropertyMetadata(true, On_IsMinuteVisible)); private static void On_IsMinuteVisible(DependencyObject d, DependencyPropertyChangedEventArgs e) { TimeSpanBox sender = d as TimeSpanBox; if (sender != null) { Grid innerGrid = (Grid)sender.Content; innerGrid.ColumnDefinitions[8].Width = e.NewValue != null && e.NewValue is bool && (bool)e.NewValue == true ? new GridLength(1, GridUnitType.Star) : new GridLength(0); innerGrid.ColumnDefinitions[9].Width = e.NewValue != null && e.NewValue is bool && (bool)e.NewValue == true ? GridLength.Auto : new GridLength(0); } } #endregion #region IsSecoundVisible public bool IsSecoundVisible { get { return (bool)GetValue(IsSecoundVisibleProperty); } set { SetValue(IsSecoundVisibleProperty, value); } } public static readonly DependencyProperty IsSecoundVisibleProperty = DependencyProperty.Register("IsSecoundVisible", typeof(bool), typeof(TimeSpanBox), new PropertyMetadata(true, On_IsSecoundVisible)); private static void On_IsSecoundVisible(DependencyObject d, DependencyPropertyChangedEventArgs e) { TimeSpanBox sender = d as TimeSpanBox; if (sender != null) { Grid innerGrid = (Grid)sender.Content; innerGrid.ColumnDefinitions[10].Width = e.NewValue != null && e.NewValue is bool && (bool)e.NewValue == true ? new GridLength(1, GridUnitType.Star) : new GridLength(0); innerGrid.ColumnDefinitions[11].Width = e.NewValue != null && e.NewValue is bool && (bool)e.NewValue == true ? GridLength.Auto : new GridLength(0); } } #endregion #region IsReadOnly public bool IsReadOnly { get { return (bool)GetValue(IsReadOnlyProperty); } set { SetValue(IsReadOnlyProperty, value); } } public static readonly DependencyProperty IsReadOnlyProperty = DependencyProperty.Register("IsReadOnly", typeof(bool), typeof(TimeSpanBox), new PropertyMetadata(false, OnIsReadOnly_Changed)); private static void OnIsReadOnly_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e) { TimeSpanBox sender = d as TimeSpanBox; if (sender != null) { bool isreadOnly = e.NewValue != null && e.NewValue is bool && (bool)e.NewValue == true; sender.txtYear.IsReadOnly = isreadOnly; sender.txtYear.IsReadOnly = isreadOnly; sender.txtYear.IsReadOnly = isreadOnly; sender.txtYear.IsReadOnly = isreadOnly; sender.txtYear.IsReadOnly = isreadOnly; sender.txtYear.IsReadOnly = isreadOnly; } } #endregion #region Year public int Year { get { return (int)GetValue(YearProperty); } set { SetValue(YearProperty, value); } } public static readonly DependencyProperty YearProperty = DependencyProperty.Register("Year", typeof(int), typeof(TimeSpanBox), new PropertyMetadata(0, On_Year_Changed)); private static void On_Year_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e) { TimeSpanBox selector = d as TimeSpanBox; if (selector != null && selector.CanRaiseTxtChaned_Year_AttachDP == true) { if (e.NewValue == null) selector.SetText_Year(""); else if (e.NewValue.GetType().Equals(typeof(int))) { selector.SetText_Year(int.Parse(e.NewValue.ToString()).ToString()); } else { selector.SetText_Year("0"); } } } #endregion #region Month public int Month { get { return (int)GetValue(MonthProperty); } set { SetValue(MonthProperty, value); } } public static readonly DependencyProperty MonthProperty = DependencyProperty.Register("Month", typeof(int), typeof(TimeSpanBox), new PropertyMetadata(0, On_Month_Changed)); private static void On_Month_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e) { TimeSpanBox selector = d as TimeSpanBox; if (selector != null && selector.CanRaiseTxtChaned_Month_AttachDP == true) { if (e.NewValue == null) selector.SetText_Month(""); else if (e.NewValue.GetType().Equals(typeof(int))) { selector.SetText_Month(int.Parse(e.NewValue.ToString()).ToString()); } else { selector.SetText_Month("0"); } } } #endregion #region Day public int Day { get { return (int)GetValue(DayProperty); } set { SetValue(DayProperty, value); } } public static readonly DependencyProperty DayProperty = DependencyProperty.Register("Day", typeof(int), typeof(TimeSpanBox), new PropertyMetadata(0, ON_Day_Changed)); private static void ON_Day_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e) { TimeSpanBox selector = d as TimeSpanBox; if (selector != null && selector.CanRaiseTxtChaned_Day_AttachDP == true) { if (e.NewValue == null) selector.SetText_Day(""); else if (e.NewValue.GetType().Equals(typeof(int))) { selector.SetText_Day(int.Parse(e.NewValue.ToString()).ToString()); } else { selector.SetText_Day("0"); } } } #endregion #region Hour public int Hour { get { return (int)GetValue(HourProperty); } set { SetValue(HourProperty, value); } } public static readonly DependencyProperty HourProperty = DependencyProperty.Register("Hour", typeof(int), typeof(TimeSpanBox), new PropertyMetadata(0, On_Hour_CHanged)); private static void On_Hour_CHanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { TimeSpanBox selector = d as TimeSpanBox; if (selector != null && selector.CanRaiseTxtChaned_Hour_AttachDP == true) { if (e.NewValue == null) selector.SetText_Hour(""); else if (e.NewValue.GetType().Equals(typeof(int))) { selector.SetText_Hour(int.Parse(e.NewValue.ToString()).ToString()); } else { selector.SetText_Hour("0"); } } } #endregion #region Minutes public int Minutes { get { return (int)GetValue(MinutesProperty); } set { SetValue(MinutesProperty, value); } } public static readonly DependencyProperty MinutesProperty = DependencyProperty.Register("Minutes", typeof(int), typeof(TimeSpanBox), new PropertyMetadata(0, On_Minute_CHanged)); private static void On_Minute_CHanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { TimeSpanBox selector = d as TimeSpanBox; if (selector != null && selector.CanRaiseTxtChaned_Minute_AttachDP == true) { if (e.NewValue == null) selector.SetText_Minute(""); else if (e.NewValue.GetType().Equals(typeof(int))) { selector.SetText_Minute(int.Parse(e.NewValue.ToString()).ToString()); } else { selector.SetText_Minute("0"); } } } #endregion #region Secound public int Secound { get { return (int)GetValue(SecoundProperty); } set { SetValue(SecoundProperty, value); } } public static readonly DependencyProperty SecoundProperty = DependencyProperty.Register("Secound", typeof(int), typeof(TimeSpanBox), new PropertyMetadata(0, On_Secound_Changed)); private static void On_Secound_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e) { TimeSpanBox selector = d as TimeSpanBox; if (selector != null && selector.CanRaiseTxtChaned_Secound_AttachDP == true) { if (e.NewValue == null) selector.SetText_Secound(""); else if (e.NewValue.GetType().Equals(typeof(int))) { selector.SetText_Secound(int.Parse(e.NewValue.ToString()).ToString()); } else { selector.SetText_Secound("0"); } } } #endregion #region 文本 public string YearText { get { return (string)GetValue(YearTextProperty); } set { SetValue(YearTextProperty, value); } } public static readonly DependencyProperty YearTextProperty = DependencyProperty.Register("YearText", typeof(string), typeof(TimeSpanBox), new PropertyMetadata("0")); public string MonthText { get { return (string)GetValue(MonthTextProperty); } set { SetValue(MonthTextProperty, value); } } public static readonly DependencyProperty MonthTextProperty = DependencyProperty.Register("MonthText", typeof(string), typeof(TimeSpanBox), new PropertyMetadata("0")); public string DayText { get { return (string)GetValue(DayTextProperty); } set { SetValue(DayTextProperty, value); } } public static readonly DependencyProperty DayTextProperty = DependencyProperty.Register("DayText", typeof(string), typeof(TimeSpanBox), new PropertyMetadata("0")); public string HourText { get { return (string)GetValue(HourTextProperty); } set { SetValue(HourTextProperty, value); } } public static readonly DependencyProperty HourTextProperty = DependencyProperty.Register("HourText", typeof(string), typeof(TimeSpanBox), new PropertyMetadata("0")); public string MinuteText { get { return (string)GetValue(MinuteTextProperty); } set { SetValue(MinuteTextProperty, value); } } public static readonly DependencyProperty MinuteTextProperty = DependencyProperty.Register("MinuteText", typeof(string), typeof(TimeSpanBox), new PropertyMetadata("0")); public string SecoundText { get { return (string)GetValue(SecoundTextProperty); } set { SetValue(SecoundTextProperty, value); } } public static readonly DependencyProperty SecoundTextProperty = DependencyProperty.Register("SecoundText", typeof(string), typeof(TimeSpanBox), new PropertyMetadata("0")); #endregion #region UpDownBtnVisible public Visibility UpDownBtnVisible { get { return (Visibility)GetValue(UpDownBtnVisibleProperty); } set { SetValue(UpDownBtnVisibleProperty, value); } } public static readonly DependencyProperty UpDownBtnVisibleProperty = DependencyProperty.Register("UpDownBtnVisible", typeof(Visibility), typeof(TimeSpanBox), new PropertyMetadata(Visibility.Collapsed, OnUpDownBtnVisible_Changed)); private static void OnUpDownBtnVisible_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e) { TimeSpanBox selector = d as TimeSpanBox; if (selector != null) { selector.gridShow.Visibility = e.NewValue != null && e.NewValue is Visibility && (Visibility)e.NewValue == Visibility.Visible ? Visibility.Visible : Visibility.Collapsed; } } #endregion #region 标题颜色 public Brush TitleBrush { get { return (Brush)GetValue(TitleBrushProperty); } set { SetValue(TitleBrushProperty, value); } } // Using a DependencyProperty as the backing store for TitleBrush. This enables animation, styling, binding, etc... public static readonly DependencyProperty TitleBrushProperty = DependencyProperty.Register("TitleBrush", typeof(Brush), typeof(TimeSpanBox), new PropertyMetadata(new SolidColorBrush(Colors.Black), on_TitleBrush_CHanged)); private static void on_TitleBrush_CHanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { TimeSpanBox sender = d as TimeSpanBox; if (sender != null && e.NewValue != null && e.NewValue is Brush) { Brush newBrush = ((Brush)e.NewValue); sender.txtbYear.Foreground = newBrush; sender.txtbMonth.Foreground = newBrush; sender.txtbDay.Foreground = newBrush; sender.txtbMinute.Foreground = newBrush; sender.txtbHour.Foreground = newBrush; sender.txtbSecound.Foreground = newBrush; } else if (e.NewValue != null || !(e.NewValue is Brush)) { sender.txtbYear.Foreground = new SolidColorBrush(Colors.Black); sender.txtbMonth.Foreground = new SolidColorBrush(Colors.Black); sender.txtbDay.Foreground = new SolidColorBrush(Colors.Black); sender.txtbMinute.Foreground = new SolidColorBrush(Colors.Black); sender.txtbHour.Foreground = new SolidColorBrush(Colors.Black); sender.txtbSecound.Foreground = new SolidColorBrush(Colors.Black); } } #endregion } }
如何使用:
xmlns:local="clr-namespace:TimeEditerDemo" .... <!--不显示年,不现实月,不显示秒,显示按钮,天时分红字,--> <local:TimeSpanBox x:Name="pick" Height="25" TitleBrush="Red" IsYearVisible="False" IsMonthVisible="False" IsSecoundVisible="False" UpDownBtnVisible="Visible"/> <TextBox x:Name="inputNum"/> <Button Content="Set Year" Click="Button_Click"/> <TextBlock Margin="0 10 0 0"> <Run Text="当前时间:"/> <Run Text="{Binding Year,ElementName=pick}"/> <Run Text="年"/> <Run Text="{Binding Month,ElementName=pick}"/> <Run Text="月"/> <Run Text="{Binding Day,ElementName=pick}"/> <Run Text="日"/> <Run Text="{Binding Hour,ElementName=pick}"/> <Run Text="时"/> <Run Text="{Binding Minutes,ElementName=pick}"/> <Run Text="分"/> <Run Text="{Binding Secound,ElementName=pick}"/> <Run Text="秒"/> </TextBlock> <x:Code> private void Button_Click(object sender, RoutedEventArgs e) { int tempValue = 0; pick.Day = int.TryParse(this.inputNum.Text, out tempValue) ? tempValue : 0; } </x:Code>
上述控件待完善: 给 Year、Month、Day、Hour、Minite、Secound、负值的时候的CoerceValueCallback
缺少对应的Year_Change Month_Change Day_Change Hour_CHange Minite_Change Secound_Chang 等事件
//本人懒的弄了,UI也没有任何优化
运行结果
Bug Fix 初始化时设置时分秒后显示值为0
原因: UserControl 种的Initial事件种如果包含的BInding是Relative,不能及时更新对应的绑定源,如下
<TextBox Grid.Column="0" BorderBrush="Transparent" BorderThickness="0" x:Name="txtYear" VerticalContentAlignment="Center" InputMethod.IsInputMethodEnabled="False" TextAlignment="Right" Padding="0,0,1,0" Text="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=local:TimeSpanBox},Path=YearText,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/>