时间跨度选择器 xaml

Posted

技术标签:

【中文标题】时间跨度选择器 xaml【英文标题】:TimeSpanPicker xaml 【发布时间】:2014-12-13 21:33:54 【问题描述】:

我需要一个 TimeSpanPicker 控件用于我的 Windows 8.1(Windows 商店)应用程序。我在 Windows 8 工具箱中找不到它。如果控件已经可用,请分享任何指向该控件的链接,或者帮助我从头开始构建它。

我在网上搜索过解决办法,但是TimeSpanPicker控件只适用于windows phone,不适用于windows 8。

如何实现循环控制 UI 来实现我自己的 TimeSpanPicker?

【问题讨论】:

如果您可以显示您已经完成和搜索的内容,您可能会收到回复。 【参考方案1】:

这可能是你的幸运日。我刚刚为时间码创建了一个微调器,我使用时间跨度作为它的值。 这有点粗略,但它可以完成工作。无论如何,它可能会为您提供有关如何构建自己的想法。

注意这是作为自定义控件构建的。我想用户控件也可以工作。

XAML:

 <Style TargetType="x:Type local:TimeCodeUpDown">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="x:Type local:TimeCodeUpDown">

                <Grid HorizontalAlignment="TemplateBinding HorizontalAlignment"
                      VerticalAlignment="TemplateBinding VerticalAlignment"
                      SnapsToDevicePixels="True"
                      >
                    <Border Background="TemplateBinding Background"
                            BorderBrush="TemplateBinding BorderBrush"
                            BorderThickness="TemplateBinding BorderThickness"
                            HorizontalAlignment="Left"
                            Padding="1"
                            >
                        <StackPanel Orientation="Horizontal" VerticalAlignment="Center">
                            <TextBox x:Name="HoursText"
                                     BorderThickness="0"
                                     VerticalAlignment="Center"
                                     Width="Auto"
                                     Text="Binding RelativeSource=RelativeSource TemplatedParent, 
                                            Path=Hours, StringFormat=0:D2, Mode=TwoWay" TabIndex="1"/>
                            <TextBox x:Name="HoursSeparator"
                                     BorderThickness="0"
                                     VerticalAlignment="Center"
                                     Text=":"/>
                            <TextBox x:Name="MinutesText"
                                     BorderThickness="0"
                                     VerticalAlignment="Center"
                                     Width="Auto"
                                     Text="Binding RelativeSource=RelativeSource TemplatedParent, 
                                            Path=Minutes, StringFormat=0:D2, Mode=TwoWay" TabIndex="2"/>
                            <TextBox x:Name="MinutesSeparator"
                                     BorderThickness="0"
                                     VerticalAlignment="Center"
                                     Text=":"/>
                            <TextBox x:Name="SecondsText"
                                     BorderThickness="0"
                                     VerticalAlignment="Center"
                                     Width="Auto"
                                     Text="Binding RelativeSource=RelativeSource TemplatedParent, 
                                            Path=Seconds, StringFormat=0:D2, Mode=TwoWay" TabIndex="3"/>
                            <TextBox x:Name="SecondsSeparator"
                                     BorderThickness="0"
                                     VerticalAlignment="Center"
                                     Text=":"/>
                            <TextBox x:Name="FramesText"
                                     BorderThickness="0"
                                     VerticalAlignment="Center"
                                     Width="Auto"
                                     Text="Binding RelativeSource=RelativeSource TemplatedParent, 
                                            Path=Frames, StringFormat=0:D2, Mode=TwoWay" TabIndex="4"/>

                            <Grid x:Name="ButtonGrid"
                                  Margin="3,0,0,0"
                                  Width="10">
                                <Grid.RowDefinitions>
                                    <RowDefinition/>
                                    <RowDefinition/>
                                </Grid.RowDefinitions>
                                <Button x:Name="UpButton" Grid.Row="0" 
                                        BorderThickness="0.5" Margin="0,0,0,0.5" 
                                        Background="Transparent">
                                        <Path Stroke="Transparent" Fill="Black"  Data="M 1 3.5 L 2.5 1 L 4 3.5 Z"/>
                                </Button>
                                <Button x:Name="DownButton" 
                                        Grid.Row="1" 
                                        BorderThickness="0.5" Margin="0,0.5,0,0" Background="Transparent">
                                        <Path Stroke="Transparent" Fill="Black"  Data="M 1 1 L 2.5 4 L 4 1 Z"/>
                                </Button>

                            </Grid>
                        </StackPanel>
                    </Border>
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
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 Stv.AutoCatch.Desktop.Client.Infrastructure.Controls

    /// <summary>
    /// Follow steps 1a or 1b and then 2 to use this custom control in a XAML file.
    ///
    /// Step 1a) Using this custom control in a XAML file that exists in the current project.
    /// Add this XmlNamespace attribute to the root element of the markup file where it is 
    /// to be used:
    ///
    ///     xmlns:MyNamespace="clr-namespace:Stv.AutoCatch.Desktop.Client.Infrastructure.Controls"
    ///
    ///
    /// Step 1b) Using this custom control in a XAML file that exists in a different project.
    /// Add this XmlNamespace attribute to the root element of the markup file where it is 
    /// to be used:
    ///
    ///     xmlns:MyNamespace="clr-namespace:Stv.AutoCatch.Desktop.Client.Infrastructure.Controls;assembly=Stv.AutoCatch.Desktop.Client.Infrastructure.Controls"
    ///
    /// You will also need to add a project reference from the project where the XAML file lives
    /// to this project and Rebuild to avoid compilation errors:
    ///
    ///     Right click on the target project in the Solution Explorer and
    ///     "Add Reference"->"Projects"->[Browse to and select this project]
    ///
    ///
    /// Step 2)
    /// Go ahead and use your control in the XAML file.
    ///
    ///     <MyNamespace:TimeCodeUpDown/>
    ///
    /// </summary>
    public class TimeCodeUpDown : Control
    
        TextBox _lastFocusedTextBox;

        internal TimeSpan InternalTime
        
            get  return _internalTime; 
        
        TimeSpan _internalTime = TimeSpan.Zero;

        static TimeCodeUpDown()
        
            DefaultStyleKeyProperty.OverrideMetadata(typeof(TimeCodeUpDown), new FrameworkPropertyMetadata(typeof(TimeCodeUpDown)));
        

        public override void OnApplyTemplate()
        
            base.OnApplyTemplate();
            Button upButton = (Button)base.GetTemplateChild("UpButton");
            Button downButton = (Button)base.GetTemplateChild("DownButton");

            upButton.Click += upButton_Click;
            downButton.Click += downButton_Click;

            TextBox hoursText = (TextBox)base.GetTemplateChild("HoursText");
            hoursText.GotFocus += _hoursText_GotFocus;

            TextBox minutesText = (TextBox)base.GetTemplateChild("MinutesText");
            minutesText.GotFocus += _minutesText_GotFocus;

            TextBox secondsText = (TextBox)base.GetTemplateChild("SecondsText");
            secondsText.GotFocus += _secondsText_GotFocus;

            TextBox framesText = (TextBox)base.GetTemplateChild("FramesText");
            framesText.GotFocus += _framesText_GotFocus;
        

        void _framesText_GotFocus(object sender, RoutedEventArgs e)
        
            _lastFocusedTextBox = (TextBox)sender;
        

        void _secondsText_GotFocus(object sender, RoutedEventArgs e)
        
            _lastFocusedTextBox = (TextBox)sender;
        

        void _minutesText_GotFocus(object sender, RoutedEventArgs e)
        
            _lastFocusedTextBox = (TextBox)sender;
        

        void _hoursText_GotFocus(object sender, RoutedEventArgs e)
        
            _lastFocusedTextBox = (TextBox)sender;
        

        void downButton_Click(object sender, RoutedEventArgs e)
        
            if (_lastFocusedTextBox != null)
            
                if (_lastFocusedTextBox.Name.Equals("HoursText"))
                
                    if (this.Hours > 0)
                        this.Hours--;
                    else if (this.Hours == 0)
                        this.Hours = 23;

                
                if (_lastFocusedTextBox.Name.Equals("MinutesText"))
                
                    if (this.Minutes > 0)
                        this.Minutes--;
                    else if (this.Minutes == 0)
                        this.Minutes = 59;
                
                if (_lastFocusedTextBox.Name.Equals("SecondsText"))
                
                    if (this.Seconds > 0)
                        this.Seconds--;
                    else if (this.Seconds == 0)
                        this.Seconds = 59;
                
                if (_lastFocusedTextBox.Name.Equals("FramesText"))
                
                    if (this.Frames > 0)
                        this.Frames--;
                    else if (this.Frames == 0)
                        this.Frames = 24;
                
            
        

        void upButton_Click(object sender, RoutedEventArgs e)
        
            if (_lastFocusedTextBox != null)
            

                if (_lastFocusedTextBox.Name.Equals("HoursText"))
                
                    if (this.Hours < 23)
                        this.Hours++;
                    else if (this.Hours == 23)
                        this.Hours = 0;

                
                if (_lastFocusedTextBox.Name.Equals("MinutesText"))
                
                    if (this.Minutes < 59)
                        this.Minutes++;
                    else if (this.Minutes == 59)
                        this.Minutes = 0;
                
                if (_lastFocusedTextBox.Name.Equals("SecondsText"))
                
                    if (this.Seconds < 59)
                        this.Seconds++;
                    else if (this.Seconds == 59)
                        this.Seconds = 0;
                
                if (_lastFocusedTextBox.Name.Equals("FramesText"))
                
                    if (this.Frames < 24)
                        this.Frames++;
                    else if (this.Frames == 24)
                        this.Frames = 0;
                
            
        

        public TimeSpan TimeValue
        
            get  return (TimeSpan)GetValue(TimeValueProperty); 
            set  SetValue(TimeValueProperty, value); 
        

        // Using a DependencyProperty as the backing store for TimeValue.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty TimeValueProperty =
            DependencyProperty.Register("TimeValue", typeof(TimeSpan), typeof(TimeCodeUpDown), new PropertyMetadata(TimeSpan.Zero, new PropertyChangedCallback(OnTimeValueChanged)));

        private static void OnTimeValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        
            var instance = (TimeCodeUpDown)d;

            TimeSpan newValue = (TimeSpan)e.NewValue;
            if (newValue < TimeSpan.Zero || newValue >= TimeSpan.FromDays(1))  // ensure TimeSpan is less than 1 day and not negative.
                newValue = new TimeSpan(0, newValue.Hours, newValue.Minutes, newValue.Seconds, newValue.Milliseconds);

            if(!instance._internalTime.Equals(newValue))
            
                // we are being changed from outside the control.
                var absoluteTime = Convert.ToInt64(25 * newValue.TotalSeconds);


                instance.Hours = Convert.ToInt32((absoluteTime / 90000) % 24);
                instance.Minutes = Convert.ToInt32((absoluteTime - (90000 * instance.Hours)) / 1500);
                instance.Seconds = Convert.ToInt32(((absoluteTime - (1500 * instance.Minutes) - (90000 * instance.Hours)) / 25));
                instance.Frames = Convert.ToInt32(absoluteTime - (25 * instance.Seconds) - (1500 * instance.Minutes) - (90000 * instance.Hours));
            
        


        //internal ICommand



        public int Hours
        
            get  return (int)GetValue(HoursProperty); 
            set  SetValue(HoursProperty, value); 
        

        // Using a DependencyProperty as the backing store for Hours.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty HoursProperty =
            DependencyProperty.Register("Hours", typeof(int), typeof(TimeCodeUpDown), new PropertyMetadata(0, new PropertyChangedCallback(OnHoursChanged)));

        private static void OnHoursChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        
            var instance = (TimeCodeUpDown)d;
            TimeSpan newTime =
                new TimeSpan(0, (int)e.NewValue, instance.TimeValue.Minutes, instance.TimeValue.Seconds, instance.TimeValue.Milliseconds);
            instance._internalTime = newTime;
            instance.TimeValue = newTime;
        



        public int Minutes
        
            get  return (int)GetValue(MinutesProperty); 
            set  SetValue(MinutesProperty, value); 
        

        // Using a DependencyProperty as the backing store for Minutes.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty MinutesProperty =
            DependencyProperty.Register("Minutes", typeof(int), typeof(TimeCodeUpDown), new PropertyMetadata(0, new PropertyChangedCallback(OnMinutesChanged)));

        private static void OnMinutesChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        
            var instance = (TimeCodeUpDown)d;
            TimeSpan newTime =
                new TimeSpan(0, instance.TimeValue.Hours, (int)e.NewValue, instance.TimeValue.Seconds, instance.TimeValue.Milliseconds);
            instance._internalTime = newTime;
            instance.TimeValue = newTime;
        




        public int Seconds
        
            get  return (int)GetValue(SecondsProperty); 
            set  SetValue(SecondsProperty, value); 
        

        // Using a DependencyProperty as the backing store for Seconds.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty SecondsProperty =
            DependencyProperty.Register("Seconds", typeof(int), typeof(TimeCodeUpDown), new PropertyMetadata(0, new PropertyChangedCallback(OnSecondsChanged)));

        private static void OnSecondsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        
            var instance = (TimeCodeUpDown)d;
            TimeSpan newTime =
                new TimeSpan(0, instance.TimeValue.Hours, instance.TimeValue.Minutes, (int)e.NewValue, instance.TimeValue.Milliseconds);
            instance._internalTime = newTime;
            instance.TimeValue = newTime;
        

        public int Frames
        
            get  return (int)GetValue(FramesProperty); 
            set  SetValue(FramesProperty, value); 
        

        // Using a DependencyProperty as the backing store for Frames.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty FramesProperty =
            DependencyProperty.Register("Frames", typeof(int), typeof(TimeCodeUpDown), new PropertyMetadata(0, new PropertyChangedCallback(OnFramesChanged)));

        private static void OnFramesChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        
            var instance = (TimeCodeUpDown)d;
            TimeSpan newTime =
                new TimeSpan(0, instance.TimeValue.Hours, instance.TimeValue.Minutes, instance.TimeValue.Seconds, (int)e.NewValue * 40);
            instance._internalTime = newTime;
            instance.TimeValue = newTime;
        


    

【讨论】:

谢谢约翰,我已经使用组合框实现了时间跨度选择器,就像微软在他们自己的日期选择器和时间选择器控件中所做的那样。它的触摸友好。你的实现很好。

以上是关于时间跨度选择器 xaml的主要内容,如果未能解决你的问题,请参考以下文章

这个 CSS 选择器是啥? [类* =“跨度”]

如何防止通用选择器规则影响跨度? [复制]

单击跨度时打开日期选择器

如何在 Scrapy 中使用多个嵌套跨度 CSS 选择器?

如何在 matplotlib 小部件的嵌入式图形上使用跨度选择器?

选择器 ItemSource 值未绑定在 XAML ListView 中