2009-12-02 9 views
17

Estoy buscando un simple selector de tiempo control para WPF.¿Cuál es actualmente el mejor selector de tiempo libre para WPF?

  • que he encontrado encontrado éste:

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

pero tiene algunos problemas por ejemplo, no puede escribir "00", el segundo cero no aparecerá.

  • Silverlight parece tener uno:

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

pero es no para WPF.

  • WPF Toolkit tiene un DatePicker pero no es un TimePicker por sí mismo. ¿O hay alguna manera de permitirle al usuario ingresar la hora y la fecha en WPFToolkit DatePicker? Es devuelve un DateTime en SelectedDate, pero no veo cómo permitir que el usuario también elija la hora con este control.

¿Cuál es el mejor control de WPF para permitir a los usuarios ingresar la hora en formato HH: MM: SS?

Respuesta

3

Puede enrollar el suyo con bastante facilidad, como se muestra en here. Y de esa manera, puedes obtener exactamente lo que quieres.

+0

Este es un buen ejemplo, simplemente tomaría la entrada del teclado y el mouse sin cambiar el código. :-) – wonea

+0

el selector de tiempo es terrible – CRice

5

No pude encontrar uno en la web, así que lo creé desde el principio. No entiendo por completo las Propiedades de dependencia, por lo tanto, las omito por ahora. El control es un control del selector de tiempo de 12 horas. Soy nuevo en WPF, por lo que no entiendo completamente todas las sintaxis del lenguaje nuevo, pero este control me servirá para el proyecto que estoy creando en casa.

Admite el tiempo de configuración como DateTime o TimeSpan.

A continuación, pegaré el XAML y el código subyacente. El 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> 

El código subyacente

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

Ese es el control, no dude en hacer modificaciones según sea necesario. No es perfecto, pero es mejor que otros controles que he encontrado

23

me gustan los controles de la caja de herramientas de WPF extendida: Link to source code on codeplex

En el paquete, el DateTimeUpDown está contenido que puede ser utilizado para su propósito. Si no desea usar la parte Date, puede configurar el Format como "ShortTime" o el formato que desee.

Espero que ayude.

+1

Los encontré muy útiles. ¡Gracias! –

+0

Debo lamentar ... No sé por qué pero usan un DateTime? por el valor del TimePicker ... que no encaja con mi modelo. Probablemente podría hacer cosas para arreglar eso, pero prefiero ir a otro control. –

+1

Lo hacen para que cuando se enlace a una columna de tabla de la base de datos, el control no tenga un ajuste cuando esa columna contenga valores nulos, como ocurre a menudo. Si su modelo no considera este escenario, quizás necesite más reflexión. –

Cuestiones relacionadas