【问题标题】:Is there a TimePicker control in WPF (.NET 4)?WPF (.NET 4) 中是否有 TimePicker 控件?
【发布时间】:2012-03-02 08:38:44
【问题描述】:

WPF (.NET 4) 中是否有 TimePicker 控件?

我希望 DatePicker 控件能够显示数据或时间或两者,但似乎并非如此。这些中的任何一个都适合我:

Wednesday, February 8th, 2012 2:27 pm

-或:

2:27 pm

(我将与 DatePicker 一起使用)

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~

更新(尝试安装扩展的 WPF 控件后):

这么多/听起来/应该不是那么容易。

当我尝试从 http://wpftoolkit.codeplex.com/releases/view/71499我进入了我的下载对话框:

http://download.codeplex.com/site/pagenotfound?ReferenceId=f1704e1d-3152-4ecf-b2bb-ace62735bcbc

(注意“找不到页面”部分 - 没有下载任何内容)。

...然后我继续计划 B 并尝试下载/安装 Nuget,这样我就可以通过这种方式获得扩展的 WPF 工具包(通过工具 | 扩展管理器 | 在线画廊 | 更新 (1) | NeGet 包管理器 |下载)。

我首先必须取消选中“保护我免受潜在恶意代码”框(或类似的东西 - 我尝试过(两次!)没有取消选中该复选框,但两次都崩溃了);然后(取消选中该框后)我在安装对话框中看到“此扩展包含带有无效证书的数字签名。”

我还是继续,终于安装了 Nuget。

所以在重新启动 Visual Studio 2010 后,我去了工具 |库包管理器 |包管理器控制台,但收到错误:包管理器控制台需要 PowerShell 2.0 运行时,在此计算机上未检测到。请从http://support.microsoft.com/kb/968929 安装 PowerShell 2.0 并重新启动 Visual Studio.rt Visual Studio。"

然后,当我去安装那个更新 (WindowsXP-KB968930-x86-ENG.exe) 时,我得到了“update/update.exe 应用程序无法在 Win32 模式下运行”。并且无法继续。

啊啊啊!!!感觉就像是星期一!

【问题讨论】:

    标签: c# wpf wpf-controls datepicker


    【解决方案1】:

    WPF 4.0 不提供开箱即用的 DateTimePicker。

    更新 我在最近的一个项目中使用了 Extended WPF Toolkit http://wpftoolkit.codeplex.com/,它包含一个不错的 DateTimePicker 控件 - http://wpftoolkit.codeplex.com/wikipage?title=DateTimePicker&referringTitle=Home

    对于这个不准确的地方,我们深表歉意。

    【讨论】:

    • 啊,混乱。 wpftoolkit.codeplex.com 是扩展 WPF 工具包。 wpf.codeplex.com 是 WPF 工具包。我不知道谁在抽什么烟……
    • 谢谢你,肯特。我会捷克出扩展的。
    • Extended WPF Toolkit 是免费的还是只有 30 天?
    • WPF 工具包上的 DateTimePicker 可以工作,但远非完美的替代品。
    • 为清楚起见,扩展 WPF 工具包是 Xceed Toolkit Plus for WPF 的免费开源版本,在 Codeplex 归档后已移至 github.com/xceedsoftware/wpftoolkit。目前没有使用时间限制,可在Microsoft Public License (Ms-PL)下获取。
    【解决方案2】:

    查看 Codeplex 上的扩展 WPF 工具包DateTimeUpDownrelated SO post)。

    【讨论】:

      【解决方案3】:

      我的简单时间控制解决方案

      TimeControl.xaml

      <UserControl x:Class="Infra.UICommon.Controls.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" 
                   xmlns:local="clr-namespace:Infra.UICommon.Controls"
                   mc:Ignorable="d" 
                   Height="Auto" Width="Auto" x:Name="UserControl" 
                   d:DesignHeight="300" d:DesignWidth="300">
          <Grid x:Name="LayoutRoot" Width="Auto" Height="Auto" Background="White">
              <Grid.ColumnDefinitions>
      
                  <ColumnDefinition Width="0.2*"/>
      
                  <ColumnDefinition Width="0.05*"/>
      
                  <ColumnDefinition Width="0.2*"/>
      
                  <ColumnDefinition Width="0.05*"/>
      
                  <ColumnDefinition Width="0.2*"/>
      
                  <ColumnDefinition Width="0.05*"/>
      
                  <ColumnDefinition Width="0.2*"/>
      
              </Grid.ColumnDefinitions>
      
              <!-- Hours -->
              <Grid x:Name="hours" Focusable="True" MouseWheel="OnMouseWheel" >
                  <TextBox x:Name="hh" TextWrapping="Wrap" Text="{Binding Path=Hours, ElementName=UserControl, Mode=Default}" 
                           PreviewKeyDown="OnKeyDown" PreviewTextInput="OnPreviewTextInput"  DataObject.Pasting="OnTextPasting" 
                           TextAlignment="Center" VerticalAlignment="Center"  BorderThickness="0"/>
              </Grid>
      
              <!-- Separator ':' -->
              <Grid  Grid.Column="1">
                  <TextBox IsReadOnly="True" x:Name="sep1" TextWrapping="Wrap" VerticalAlignment="Center" Text=":" TextAlignment="Center"  BorderThickness="0"/>
              </Grid>
      
              <!-- Minutes -->
              <Grid  Grid.Column="2" x:Name="minutes" Focusable="True" MouseWheel="OnMouseWheel">
                  <TextBox  x:Name="mm"  TextWrapping="Wrap" Text="{Binding Path=Minutes, ElementName=UserControl, Mode=Default}" 
                            PreviewKeyDown="OnKeyDown" PreviewTextInput="OnPreviewTextInput"  DataObject.Pasting="OnTextPasting" 
                            TextAlignment="Center" VerticalAlignment="Center" BorderThickness="0" />
              </Grid>
      
              <!-- Separator ':' -->
              <Grid  Grid.Column="3">
                  <TextBox IsReadOnly="True" x:Name="sep2"  TextWrapping="Wrap" VerticalAlignment="Center" Text=":" TextAlignment="Center"  BorderThickness="0"/>
              </Grid>
      
              <!-- Seconds -->
              <Grid  Grid.Column="4" Name="seconds" Focusable="True" MouseWheel="OnMouseWheel">
                  <TextBox x:Name="ss"  TextWrapping="Wrap" Text="{Binding Path=Seconds, ElementName=UserControl, Mode=Default}" 
                           PreviewKeyDown="OnKeyDown" PreviewTextInput="OnPreviewTextInput"  DataObject.Pasting="OnTextPasting" 
                           TextAlignment="Center" VerticalAlignment="Center" BorderThickness="0" />
              </Grid>
      
              <!-- Separator ':' -->
              <Grid  Grid.Column="5">
                  <TextBox IsReadOnly="True" x:Name="sep3"  TextWrapping="Wrap" VerticalAlignment="Center"  Text=":" TextAlignment="Center"  BorderThickness="0"/>
              </Grid>
      
              <!-- Milliseconds -->
              <Grid  Grid.Column="6" Name="miliseconds" Focusable="True" MouseWheel="OnMouseWheel">
                  <TextBox x:Name="ff"  TextWrapping="Wrap" Text="{Binding Path=Milliseconds, ElementName=UserControl, Mode=Default}"
                           PreviewKeyDown="OnKeyDown" PreviewTextInput="OnPreviewTextInput"  DataObject.Pasting="OnTextPasting" 
                           TextAlignment="Center" VerticalAlignment="Center" BorderThickness="0" />
              </Grid>
      
          </Grid>
      
      </UserControl>
      

      TimeControl.xaml.cs(代码隐藏)

      namespace Infra.UICommon.Controls
      {
          /// <summary>
          /// Interaction logic for TimeControl.xaml
          /// </summary>
          public partial class TimeControl : UserControl
          {
              public TimeControl()
              {
                  InitializeComponent();
              }
      
              private static void OnValueChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
              {
                  TimeControl control = obj as TimeControl;
                  var newTime = (TimeSpan)e.NewValue;
      
                  control.Hours        = newTime.Hours;
                  control.Minutes      = newTime.Minutes;
                  control.Seconds      = newTime.Seconds;
                  control.Milliseconds = newTime.Milliseconds;
              }
      
      
              private static void OnTimeChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
              {
                  TimeControl control = obj as TimeControl;
                  control.Value = new TimeSpan(0, control.Hours, control.Minutes, control.Seconds, control.Milliseconds);
              }
      
              public TimeSpan Value
              {
                  get { return (TimeSpan)GetValue(ValueProperty); }
                  set { SetValue(ValueProperty, value); }
              }
              public static readonly DependencyProperty ValueProperty =
              DependencyProperty.Register("Value", typeof(TimeSpan), typeof(TimeControl),
              new FrameworkPropertyMetadata(DateTime.Now.TimeOfDay, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, new PropertyChangedCallback(OnValueChanged)));
      
      
      
              public int Hours
              {
                  get { return (int)GetValue(HoursProperty); }
                  set { SetValue(HoursProperty, value); }
              }
              public static readonly DependencyProperty HoursProperty =
              DependencyProperty.Register("Hours", typeof(int), typeof(TimeControl),
              new FrameworkPropertyMetadata(0, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, new PropertyChangedCallback(OnTimeChanged)));
      
              public int Minutes
              {
                  get { return (int)GetValue(MinutesProperty); }
                  set { SetValue(MinutesProperty, value); }
              }
              public static readonly DependencyProperty MinutesProperty =
              DependencyProperty.Register("Minutes", typeof(int), typeof(TimeControl),
              new FrameworkPropertyMetadata(0, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, new PropertyChangedCallback(OnTimeChanged)));
      
              public int Seconds
              {
                  get { return (int)GetValue(SecondsProperty); }
                  set { SetValue(SecondsProperty, value); }
              }
      
              public static readonly DependencyProperty SecondsProperty =
              DependencyProperty.Register("Seconds", typeof(int), typeof(TimeControl),
              new FrameworkPropertyMetadata(0, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, new PropertyChangedCallback(OnTimeChanged)));
      
      
              public int Milliseconds
              {
                  get { return (int)GetValue(MillisecondsProperty); }
                  set { SetValue(MillisecondsProperty, value); }
              }
      
              public static readonly DependencyProperty MillisecondsProperty =
              DependencyProperty.Register("Milliseconds", typeof(int), typeof(TimeControl),
              new FrameworkPropertyMetadata(0, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, new PropertyChangedCallback(OnTimeChanged)));
      
      
              private Tuple<int, int> GetMaxAndCurentValues(String name)
              {
                  int maxValue = 0;
                  int currValue = 0;
      
                  switch (name)
                  {
                      case "ff":
                          maxValue = 1000;
                          currValue = Milliseconds; 
                          break;
      
                      case "ss":
                          maxValue = 60;
                          currValue = Seconds;
                          break;
      
                      case "mm":
                          maxValue = 60;
                          currValue = Minutes;
                          break;
      
                      case "hh":
                          maxValue = 24;
                          currValue = Hours;
                          break;
                  }
      
                  return new Tuple<int, int>(maxValue, currValue);
              }
      
              private void UpdateTimeValue(String name, int delta)
              {
                  var values = GetMaxAndCurentValues(name);
                  int maxValue = values.Item1;
                  int currValue = values.Item2;
      
                  // Set new value
                  int newValue = currValue + delta;
      
                  if (newValue == maxValue)
                  {
                      newValue = 0;
                  }
                  else if (newValue < 0)
                  {
                      newValue += maxValue;
                  }
      
      
                  switch (name)
                  {
                      case "ff":
                          Milliseconds = newValue;
      
                          break;
      
                      case "ss":
                          Seconds = newValue;
                          break;
      
                      case "mm":
                          Minutes = newValue;
                          break;
      
                      case "hh":
                          Hours = newValue;
                          break;
                  }
              }
      
              private void OnKeyDown(object sender, KeyEventArgs args)
              {
                  try
                  {
                      int delta = 0;
                      String name = ((TextBox)sender).Name;
      
                      if (args.Key == Key.Up) { delta = 1; }
                      else if (args.Key == Key.Down) { delta = -1; }
      
                      UpdateTimeValue(name, delta);
                  }
                  catch { }
              }
      
              private void OnMouseWheel(object sender, MouseWheelEventArgs e)
              {
                  try
                  {
                      var g = (Grid)(sender);
                      var value = g.Children.OfType<TextBox>().FirstOrDefault();
      
                      UpdateTimeValue(value.Name, e.Delta / Math.Abs(e.Delta));
                  }
                  catch { }
      
              }
      
              private Boolean IsTextAllowed(String name, String text)
              {
                  try
                  {
                      foreach (Char c in text.ToCharArray())
                      {
                          if (Char.IsDigit(c) || Char.IsControl(c)) continue;
                          else return false;
                      }
      
                      var values = GetMaxAndCurentValues(name);
                      int maxValue = values.Item1;
      
                      int newValue = Convert.ToInt32(text);
      
                      if (newValue < 0 || newValue >= (Int32)maxValue)
                      {
                          return false;
                      }
      
                  } catch
                  {
                      return false;
                  }
      
      
                  return true;
              }
      
              // Use the OnPreviewTextInput to respond to key presses 
              private void OnPreviewTextInput(Object sender, TextCompositionEventArgs e)
              {
                  try
                  {
                      var tb = (TextBox)sender;
      
      
                      e.Handled = !IsTextAllowed(tb.Name, tb.Text + e.Text);
                  }
                  catch { }
              }
      
              // Use the DataObject.Pasting Handler  
              private void OnTextPasting(object sender, DataObjectPastingEventArgs e)
              {
                  try
                  {
                      String name = ((TextBox)sender).Name;
      
                      if (e.DataObject.GetDataPresent(typeof(String)))
                      {
                          String text = (String)e.DataObject.GetData(typeof(String));
                          if (!IsTextAllowed(name, text)) e.CancelCommand();
                      }
                      else e.CancelCommand();
                  }
                  catch { }
              }
      
          }
      }
      

      用法:

      <ctrl:TimeControl Value="{Binding StartTime, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" x:Name="startTime"/>
      

      其中“ctrl”是 TimeControl 所在的命名空间,“StartTime”是“TimeSpan”类型的属性。

      xmlns:ctrl="clr-namespace:Infra.UICommon.Controls;assembly=Infra.UICommon"
      

      希望这会有所帮助)

      附言 这里唯一没有处理的是“退格”和“删除”键。

      【讨论】:

        【解决方案4】:

        如果您确实想要一个没有外部控件(没有扩展工具包和额外许可)的 DateTimePicker 并且也用于商业用途,我已经改进了一个现有的并在此处分享: https://gist.github.com/Apflkuacha/406e755c8b42a70b7ab138e6b985bcdf

        它看起来像这样,一个显示所选日期和时间的字段以及一个用于选择日期和时间的弹出窗口:

        【讨论】:

          【解决方案5】:

          WPF 没有正式制作,但你可以看看这个人做了什么:
          WPF Time Picker

          或者你可以自己做

          【讨论】:

            猜你喜欢
            • 2012-08-10
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-04-23
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多