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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/9218258/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-09 06:24:48  来源:igfitidea点击:

Is there a TimePicker control in WPF (.NET 4)?

c#wpfwpf-controlsdatepicker

提问by B. Clay Shannon

Is there a TimePicker control in WPF (.NET 4)?

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

I was hoping the DatePicker control had the ability to show either a data or a time or both, but it doesn't seem so. Either of these would fit the bill for me:

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

Wednesday, February 8th, 2012 2:27 pm

-or:

-或者:

2:27 pm

(which I would use in conjunction with a DatePicker)

(我将与 DatePicker 结合使用)

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

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

Updated (after trying to install the extended WPF controls):

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

So much for that / that is not as easy it sounds/should be.

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

When I tried to download the extended WPF Toolkit from http://wpftoolkit.codeplex.com/releases/view/71499I got in my download dialog:

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

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

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

(note the "page not found" part - nothing downloaded).

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

...so then I proceeded to plan B and tried to download/install Nuget, so I could get the extended WPF Toolkit that way (via Tools | Extension Manager | Online Gallery | Updates (1) | NeGet Package Manager | Download).

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

I first had to uncheck the box saying "protect me from potentially malicious code" (or something to that effect - I'd tried it (twice!) without unchecking that checkbox, and it crashed both times); and then (after unchecking the box) I saw in the install dialog, "This extension contains a digital signature with an invalid certificate."

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

I continued anyway, and finally got Nuget installed.

无论如何我继续,最后安装了Nuget。

So after restarting Visual Studio 2010 I went to Tools | Library Package Manager | Package Manager Console, but was greeted with the Error: The Package Manager Console requires PowerShell 2.0 runtime, which is not detected on this machine. Please install the PowerShell 2.0 from http://support.microsoft.com/kb/968929and restart Visual Studio.rt Visual Studio."

因此,在重新启动 Visual Studio 2010 后,我转到了 Tools | 库包管理器 | 包管理器控制台,但遇到错误:包管理器控制台需要 PowerShell 2.0 运行时,这台机器上未检测到。请从http://support.microsoft.com/kb/968929安装 PowerShell 2.0并重新启动 Visual Studio.rt Visual Studio。”

Then, when I went to install that update (WindowsXP-KB968930-x86-ENG.exe), I got, "The update/update.exe application cannot be run in Win32 mode." and it failed to proceed.

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

Achhh!!! It feels like a Monday!

啊啊啊!!!感觉像周一!

采纳答案by d_schnell

WPF 4.0 doesn't provide a DateTimePicker out of the box.

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

UpdatedI'm used the ExtendedWPF Toolkit http://wpftoolkit.codeplex.com/in an recent project it includes a nice DateTimePicker Control - http://wpftoolkit.codeplex.com/wikipage?title=DateTimePicker&referringTitle=Home.

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

Sorry for this inaccuracy.

很抱歉这个不准确。

回答by MyKuLLSKI

WPF doesn't formally make one but you can check out what this guy did:
WPF Time Picker

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

Or you can make your own

或者你可以自己制作

回答by SliverNinja - MSFT

Checkout the Extended WPF Toolkit DateTimeUpDownon Codeplex (or related SO post).

在 Codeplex(相关的 SO 帖子)上查看 Extended WPF Toolkit DateTimeUpDown

回答by Yuri Dosovitsky

My solution for simple time control

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

TimeControl.xaml

时间控制.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 (code behind)

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

    }
}

Usage:

用法:

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

Where 'ctrl' is the namespace where the TimeControl is located, and 'StartTime' is a property of the type 'TimeSpan'.

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

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

Hope this helps)

希望这可以帮助)

p.s. The only thing that's not handled here is the 'backspace' and 'delete' keys.

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