2009-12-02 89 views
17

我正在尋找一個簡單的時間選擇器控制WPF。什麼是WPF最好的空閒時間選擇器?

  • 我發現找到一個:

http://marlongrech.wordpress.com/2007/11/18/time-picker/

但它有一些問題例如你不能輸入「00」,第二個零不會出現。

  • Silverlight的似乎有一個:

http://jesseliberty.com/2009/03/28/toolkit-control-%E2%80%93-timepicker/

但它不是WPF

  • WPF Toolkit本身具有DatePicker,但不包含TimePicker。或者有沒有辦法讓用戶在WPFToolkit DatePicker中輸入時間和日期?它返回在SelectedDate的DateTime,但我看不到如何讓用戶也選擇與此控件的時間。

什麼是最好的免費WPF控件,允許用戶輸入HH:MM:SS格式的時間?

回答

3

你可以很容易地滾動你自己的here。這樣,你就可以得到你想要的東西。

+0

這是一個很好的例子,我只需要鍵盤和鼠標輸入而不用改變代碼。 :-) – wonea 2010-11-16 10:32:36

+0

時間選擇器是可怕的 – CRice 2015-08-14 06:02:04

5

我在網上找不到一個,所以我從頭開始創建它。我不完全理解依賴屬性,所以現在我省略了這些屬性。該控件是一個12小時時間選擇器控件。我是WPF的新手,所以我沒有完全理解所有新語言的語法,但是這個控制在我創建的項目中對我來說是個訣竅。

它支持將時間設置爲DateTime或TimeSpan。

下面我將粘貼XAML和Code-Behind。 的XAML

<UserControl x:Class="WorkDayManager3.WPF.UserControls.TimeControl" 
      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" 
      mc:Ignorable="d" 
      d:DesignHeight="35" d:DesignWidth="100"> 
    <Border BorderBrush="LightBlue" BorderThickness="1" Margin="1"> 
     <Grid> 
      <Grid.ColumnDefinitions> 
       <ColumnDefinition /> 
       <ColumnDefinition Width="5" /> 
       <ColumnDefinition /> 
       <ColumnDefinition /> 
       <ColumnDefinition /> 
      </Grid.ColumnDefinitions> 
      <TextBox x:Name="txtHours" BorderThickness="0" MaxLength="2" TextAlignment="Center" HorizontalAlignment="Center" VerticalAlignment="Center" Text="1" KeyUp="txt_KeyUp" MouseWheel="txt_MouseWheel" PreviewKeyUp="txt_PreviewKeyUp" /> 
      <TextBlock Text=":" Grid.Column="1" HorizontalAlignment="Center" VerticalAlignment="Center" /> 
      <TextBox x:Name="txtMinutes" BorderThickness="0" MaxLength="2" TextAlignment="Center" Grid.Column="2" HorizontalAlignment="Center" VerticalAlignment="Center" Text="00" KeyUp="txt_KeyUp" MouseWheel="txt_MouseWheel" PreviewKeyUp="txt_PreviewKeyUp" /> 
      <TextBox x:Name="txtAmPm" BorderThickness="0" MaxLength="2" TextAlignment="Center" Grid.Column="3" HorizontalAlignment="Left" VerticalAlignment="Center" PreviewTextInput="txtAmPm_PreviewTextInput" Text="AM" KeyUp="txt_KeyUp" MouseWheel="txt_MouseWheel" Padding="0, 0, 3, 0" /> 
      <Grid Grid.Column="4"> 
       <Grid.RowDefinitions> 
        <RowDefinition /> 
        <RowDefinition /> 
       </Grid.RowDefinitions> 
       <Button x:Name="btnUp" Focusable="False" Click="btnUp_Click"> 
        <TextBlock Text="p" FontFamily="Wingdings 3" HorizontalAlignment="Center" VerticalAlignment="Center" /> 
       </Button> 
       <Button x:Name="btnDown" Grid.Row="1" Focusable="False" Click="btnDown_Click"> 
        <TextBlock Text="q" FontFamily="Wingdings 3" HorizontalAlignment="Center" VerticalAlignment="Center" /> 
       </Button> 
      </Grid> 
     </Grid> 
    </Border> 
</UserControl> 

代碼隱藏

using System; 
using System.Linq; 
using System.Windows; 
using System.Windows.Controls; 
using System.Windows.Input; 

namespace WorkDayManager3.WPF.UserControls 
{ 
    /// <summary> 
    /// Interaction logic for TimeControl.xaml 
    /// </summary> 
    public partial class TimeControl : UserControl 
    { 
     public TimeControl() 
     { 
      InitializeComponent(); 
     } 

     #region Properties 

     /// <summary> 
     /// Gets or sets the date time value. 
     /// </summary> 
     /// <value>The date time value.</value> 
     public DateTime? DateTimeValue 
     { 
      get 
      { 
       string hours = this.txtHours.Text; 
       string minutes = this.txtMinutes.Text; 
       string amPm = this.txtAmPm.Text; 
       if (!string.IsNullOrWhiteSpace(hours) 
        && !string.IsNullOrWhiteSpace(minutes) 
        && !string.IsNullOrWhiteSpace(amPm)) 
       { 
        string value = string.Format("{0}:{1} {2}", this.txtHours.Text, this.txtMinutes.Text, this.txtAmPm.Text); 
        DateTime time = DateTime.Parse(value); 
        return time; 
       } 
       else 
       { 
        return null; 
       } 
      } 
      set 
      { 
       DateTime? time = value; 
       if (time.HasValue) 
       { 
        string timeString = time.Value.ToShortTimeString(); 
        //9:54 AM 
        string[] values = timeString.Split(':', ' '); 
        if (values.Length == 3) 
        { 
         this.txtHours.Text = values[0]; 
         this.txtMinutes.Text = values[1]; 
         this.txtAmPm.Text = values[2]; 
        } 
       } 
      } 
     } 

     /// <summary> 
     /// Gets or sets the time span value. 
     /// </summary> 
     /// <value>The time span value.</value> 
     public TimeSpan? TimeSpanValue 
     { 
      get 
      { 
       DateTime? time = this.DateTimeValue; 
       if (time.HasValue) 
       { 
        return new TimeSpan(time.Value.Ticks); 
       } 
       else 
       { 
        return null; 
       } 
      } 
      set 
      { 
       TimeSpan? timeSpan = value; 
       if (timeSpan.HasValue) 
       { 
        this.DateTimeValue = new DateTime(timeSpan.Value.Ticks); 
       } 
      } 
     } 

     #endregion 

     #region Event Subscriptions 

     /// <summary> 
     /// Handles the Click event of the btnDown control. 
     /// </summary> 
     /// <param name="sender">The source of the event.</param> 
     /// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param> 
     private void btnDown_Click(object sender, RoutedEventArgs e) 
     { 
      string controlId = this.GetControlWithFocus().Name; 
      if ("txtHours".Equals(controlId)) 
      { 
       this.ChangeHours(false); 
      } 
      else if ("txtMinutes".Equals(controlId)) 
      { 
       this.ChangeMinutes(false); 
      } 
      else if ("txtAmPm".Equals(controlId)) 
      { 
       this.ToggleAmPm(); 
      } 
     } 

     /// <summary> 
     /// Handles the Click event of the btnUp control. 
     /// </summary> 
     /// <param name="sender">The source of the event.</param> 
     /// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param> 
     private void btnUp_Click(object sender, RoutedEventArgs e) 
     { 
      string controlId = this.GetControlWithFocus().Name; 
      if ("txtHours".Equals(controlId)) 
      { 
       this.ChangeHours(true); 
      } 
      else if ("txtMinutes".Equals(controlId)) 
      { 
       this.ChangeMinutes(true); 
      } 
      else if ("txtAmPm".Equals(controlId)) 
      { 
       this.ToggleAmPm(); 
      } 
     } 

     /// <summary> 
     /// Handles the PreviewTextInput event of the txtAmPm control. 
     /// </summary> 
     /// <param name="sender">The source of the event.</param> 
     /// <param name="e">The <see cref="System.Windows.Input.TextCompositionEventArgs"/> instance containing the event data.</param> 
     private void txtAmPm_PreviewTextInput(object sender, TextCompositionEventArgs e) 
     { 
      // prevent users to type text 
      e.Handled = true; 
     } 

     /// <summary> 
     /// Handles the KeyUp event of the txt control. 
     /// </summary> 
     /// <param name="sender">The source of the event.</param> 
     /// <param name="e">The <see cref="System.Windows.Input.KeyEventArgs"/> instance containing the event data.</param> 
     private void txt_KeyUp(object sender, KeyEventArgs e) 
     { 
      // check for up and down keyboard presses 
      if (Key.Up.Equals(e.Key)) 
      { 
       btnUp_Click(this, null); 
      } 
      else if (Key.Down.Equals(e.Key)) 
      { 
       btnDown_Click(this, null); 
      } 
     } 

     /// <summary> 
     /// Handles the MouseWheel event of the txt control. 
     /// </summary> 
     /// <param name="sender">The source of the event.</param> 
     /// <param name="e">The <see cref="System.Windows.Input.MouseWheelEventArgs"/> instance containing the event data.</param> 
     private void txt_MouseWheel(object sender, MouseWheelEventArgs e) 
     { 
      if (e.Delta > 0) 
      { 
       btnUp_Click(this, null); 
      } 
      else 
      { 
       btnDown_Click(this, null); 
      } 
     } 

     /// <summary> 
     /// Handles the PreviewKeyUp event of the txt control. 
     /// </summary> 
     /// <param name="sender">The source of the event.</param> 
     /// <param name="e">The <see cref="System.Windows.Input.KeyEventArgs"/> instance containing the event data.</param> 
     private void txt_PreviewKeyUp(object sender, KeyEventArgs e) 
     { 
      TextBox textBox = (TextBox)sender; 
      // make sure all characters are number 
      bool allNumbers = textBox.Text.All(Char.IsNumber); 
      if (!allNumbers) 
      { 
       e.Handled = true; 
       return; 
      } 


      // make sure user did not enter values out of range 
      int value; 
      int.TryParse(textBox.Text, out value); 
      if ("txtHours".Equals(textBox.Name) && value > 12) 
      { 
       EnforceLimits(e, textBox); 
      } 
      else if ("txtMinutes".Equals(textBox.Name) && value > 59) 
      { 
       EnforceLimits(e, textBox); 
      } 
     } 

     #endregion 

     #region Methods 

     /// <summary> 
     /// Changes the hours. 
     /// </summary> 
     /// <param name="isUp">if set to <c>true</c> [is up].</param> 
     private void ChangeHours(bool isUp) 
     { 
      int value = Convert.ToInt32(this.txtHours.Text); 
      if (isUp) 
      { 
       value += 1; 
       if (value == 13) 
       { 
        value = 1; 
       } 
      } 
      else 
      { 
       value -= 1; 
       if (value == 0) 
       { 
        value = 12; 
       } 
      } 
      this.txtHours.Text = Convert.ToString(value); 
     } 

     /// <summary> 
     /// Changes the minutes. 
     /// </summary> 
     /// <param name="isUp">if set to <c>true</c> [is up].</param> 
     private void ChangeMinutes(bool isUp) 
     { 
      int value = Convert.ToInt32(this.txtMinutes.Text); 
      if (isUp) 
      { 
       value += 1; 
       if (value == 60) 
       { 
        value = 0; 
       } 
      } 
      else 
      { 
       value -= 1; 
       if (value == -1) 
       { 
        value = 59; 
       } 
      } 

      string textValue = Convert.ToString(value); 
      if (value < 10) 
      { 
       textValue = "0" + Convert.ToString(value); 
      } 
      this.txtMinutes.Text = textValue; 
     } 

     /// <summary> 
     /// Enforces the limits. 
     /// </summary> 
     /// <param name="e">The <see cref="System.Windows.Input.KeyEventArgs"/> instance containing the event data.</param> 
     /// <param name="textBox">The text box.</param> 
     /// <param name="enteredValue">The entered value.</param> 
     private static void EnforceLimits(KeyEventArgs e, TextBox textBox) 
     { 
      string enteredValue = GetEnteredValue(e.Key); 
      string text = textBox.Text.Replace(enteredValue, ""); 
      if (string.IsNullOrEmpty(text)) 
      { 
       text = enteredValue; 
      } 
      textBox.Text = text; 
      e.Handled = true; 
     } 

     /// <summary> 
     /// Gets the control with focus. 
     /// </summary> 
     /// <returns></returns> 
     private TextBox GetControlWithFocus() 
     { 
      TextBox txt = new TextBox(); 
      if (this.txtHours.IsFocused) 
      { 
       txt = this.txtHours; 
      } 
      else if (this.txtMinutes.IsFocused) 
      { 
       txt = this.txtMinutes; 
      } 
      else if (this.txtAmPm.IsFocused) 
      { 
       txt = this.txtAmPm; 
      } 
      return txt; 
     } 

     /// <summary> 
     /// Gets the entered value. 
     /// </summary> 
     /// <param name="key">The key.</param> 
     /// <returns></returns> 
     private static string GetEnteredValue(Key key) 
     { 
      string value = string.Empty; 
      switch (key) 
      { 
       case Key.D0: 
       case Key.NumPad0: 
        value = "0"; 
        break; 
       case Key.D1: 
       case Key.NumPad1: 
        value = "1"; 
        break; 
       case Key.D2: 
       case Key.NumPad2: 
        value = "2"; 
        break; 
       case Key.D3: 
       case Key.NumPad3: 
        value = "3"; 
        break; 
       case Key.D4: 
       case Key.NumPad4: 
        value = "4"; 
        break; 
       case Key.D5: 
       case Key.NumPad5: 
        value = "5"; 
        break; 
       case Key.D6: 
       case Key.NumPad6: 
        value = "6"; 
        break; 
       case Key.D7: 
       case Key.NumPad7: 
        value = "7"; 
        break; 
       case Key.D8: 
       case Key.NumPad8: 
        value = "8"; 
        break; 
       case Key.D9: 
       case Key.NumPad9: 
        value = "9"; 
        break; 
      } 
      return value; 
     } 

     /// <summary> 
     /// Toggles the am pm. 
     /// </summary> 
     private void ToggleAmPm() 
     { 
      if ("AM".Equals(this.txtAmPm.Text)) 
      { 
       this.txtAmPm.Text = "PM"; 
      } 
      else 
      { 
       this.txtAmPm.Text = "AM"; 
      } 
     } 

     #endregion 
    } 
} 

這就是控制,隨時根據需要進行修改。它並不完美,但它是我發現

23

我喜歡從擴展WPF工具的控制比其他控制好:Link to source code on codeplex

在包中,DateTimeUpDown包含可用於你的目的。如果您不想使用Date部分,則可以將Format設置爲「ShortTime」或任何您想要的格式。

希望有所幫助。

+1

我發現它們非常有用。謝謝! – 2011-11-08 13:33:08

+0

我必須後悔...我不知道爲什麼,但他們使用DateTime? TimePicker的值不符合我的模型。也許我可以做些事來解決這個問題,但我更喜歡去另一個控制。 – 2011-11-09 18:26:09

+1

他們這樣做,以便當您綁定到數據庫表列時,該控件不適合當該列包含空值時,他們經常這樣做。如果你的模型不考慮這種情況,那麼可能需要更多的思考。 – 2013-01-02 06:09:29