1

I am developing UWP App (Win10 VS2015). I have two problems.

1- How can I get the time in this format (4:00 PM or 9:34 AM etc..) in 12hours format, I can get the value without PM/AM via this TimePicker.Time = sender.Time.ToString(@"hh\:mm"), but I need the actual format as I mentioned.

XAML Code

<TimePicker ClockIdentifier="12HourClock" TimeChanged="TimePicker_TimeChanged" Style="{StaticResource TimePickerStyleCustom}"/>

.cs Code

private void TimePicker_TimeChanged(object sender, TimePickerValueChangedEventArgs e)
    {            
        timeTitle.Text = (sender as TimePicker).Time.ToString(@"hh\:mm");
    }

Via the above code, I can get the value without AM/PM and also it is in 24hour format i.e. 4:00PM is in 16:00, but I need it in 4:00PM or 4:00AM (this is just an example). If I put .ToString(@"hh\:mm tt"); it throws exception. How to get this please.

2- 2nd problem is, When we tap on the Timepicker, a TimePickerFlyout expands and we select time by clicking on hours/minutes and when finalize then click on the (Tick) Mark to select Time ... but I need to remove these buttons (Done (_/) & Cancel (X)) and select time by selecting the Hour/Min in Flyout panel rather than button click and assign it to a string. I can remove the buttons from TimePickerFlyoutPresenter Style but then how to make the Selection functional like button click.

See the screenshot, in first portion the 2 buttons are available and it worked, but I need the 2nd portion as shown in the right side.

enter image description here

Zia Ur Rahman
  • 1,850
  • 1
  • 21
  • 30

1 Answers1

1

For First problem TimeSpan represents a time interval not a time of day. You have to convert it to DateTime then format it

 private void TestTimePicker_TimeChanged(object sender, TimePickerValueChangedEventArgs e)
        {
          string Text = (sender as TimePicker).Time.ToString(@"hh\:mm");
            var dateTime = new DateTime((sender as TimePicker).Time.Ticks); // Date part is 01-01-0001
            var formattedTime = dateTime.ToString("h:mm tt", CultureInfo.InvariantCulture);
        }

Problem 2 For this either you have to implement your own TimerPickerFlyout from PickerFlyoutBase or from Flyout. It is bit complicated and I havent worked on that. You can watch this link for that

There is a easy workaround . As you mentioned in question you have to edit TimePickerFlyoutPresenter style.

I tried adding Tapped event handler to FirstPickerHost,SecondPickerHost,ThirdPickerHost.But you cant add event handlers in app.xaml. So i used Behavioural SDK's interactions. If you have Template10 used in your project you dont have to download anything just add following namespaces in app.xaml

xmlns:interact="using:Microsoft.Xaml.Interactivity" 
xmlns:interactcore="using:Microsoft.Xaml.Interactions.Core"



 <Style TargetType="TimePickerFlyoutPresenter">
        <Setter Property="Width" Value="242" />
        <Setter Property="MinWidth" Value="242" />
        <Setter Property="MaxHeight" Value="396" />
        <Setter Property="FontFamily" Value="{ThemeResource ContentControlThemeFontFamily}" />
        <Setter Property="FontWeight" Value="Normal" />
        <Setter Property="IsTabStop" Value="False" />
        <Setter Property="Background" Value="{ThemeResource SystemControlBackgroundChromeMediumLowBrush}" />
        <Setter Property="AutomationProperties.AutomationId" Value="TimePickerFlyoutPresenter" />
        <Setter Property="BorderBrush" Value="{ThemeResource SystemControlForegroundTransparentBrush}" />
        <Setter Property="BorderThickness" Value="{ThemeResource DateTimeFlyoutBorderThickness}" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="TimePickerFlyoutPresenter">
                    <Border x:Name="Background"
                        Background="{TemplateBinding Background}"
                        BorderBrush="{TemplateBinding BorderBrush}"
                        BorderThickness="{TemplateBinding BorderThickness}"
                        MaxHeight="396">
                        <Grid x:Name="ContentPanel">
                            <Grid.RowDefinitions>
                                <RowDefinition Height="*" />
                           </Grid.RowDefinitions>

                            <Grid >
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition Width="*" x:Name="FirstPickerHostColumn" />
                                    <ColumnDefinition Width="Auto" />
                                    <ColumnDefinition Width="*" x:Name="SecondPickerHostColumn" />
                                    <ColumnDefinition Width="Auto" />
                                    <ColumnDefinition Width="*" x:Name="ThirdPickerHostColumn" />
                                </Grid.ColumnDefinitions>

                                <Rectangle x:Name="HighlightRect" Fill="{ThemeResource SystemControlHighlightListAccentLowBrush}" Grid.Column="0" Grid.ColumnSpan="5" VerticalAlignment="Center" Height="44"  >

                                </Rectangle>

                                <Border x:Name="FirstPickerHost" Grid.Column="0" >
                                    <interact:Interaction.Behaviors>
                                        <interactcore:EventTriggerBehavior EventName="Tapped">
                                            <interactcore:InvokeCommandAction Command="{Binding ClosePopUp}"/>
                                        </interactcore:EventTriggerBehavior>
                                    </interact:Interaction.Behaviors>
                                </Border>
                                <Rectangle x:Name="FirstPickerSpacing" Fill="{ThemeResource SystemControlForegroundBaseLowBrush}" HorizontalAlignment="Center" Width="2" Grid.Column="1" >

                                </Rectangle>
                                <Border x:Name="SecondPickerHost" Grid.Column="2" >
                                    <interact:Interaction.Behaviors>
                                        <interactcore:EventTriggerBehavior EventName="Tapped">
                                            <interactcore:InvokeCommandAction Command="{Binding ClosePopUp}"/>
                                        </interactcore:EventTriggerBehavior>
                                    </interact:Interaction.Behaviors>
                                </Border>
                                <Rectangle x:Name="SecondPickerSpacing" Fill="{ThemeResource SystemControlForegroundBaseLowBrush}" HorizontalAlignment="Center" Width="2" Grid.Column="3" >

                                </Rectangle>
                                <Border x:Name="ThirdPickerHost" Grid.Column="4" >
                                    <interact:Interaction.Behaviors>
                                        <interactcore:EventTriggerBehavior EventName="Tapped">
                                            <interactcore:InvokeCommandAction Command="{Binding ClosePopUp}"/>
                                        </interactcore:EventTriggerBehavior>
                                    </interact:Interaction.Behaviors>
                                </Border>

                            </Grid>

                            <Grid Grid.Row="1"  Visibility="Collapsed">
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition Width="*" />
                                    <ColumnDefinition Width="*" />
                                </Grid.ColumnDefinitions>
                                <Rectangle Height="2" VerticalAlignment="Top" Fill="{ThemeResource SystemControlForegroundBaseLowBrush}" Grid.ColumnSpan="2" />

                                <Button x:Name="AcceptButton" Grid.Column="0" Content="&#xE8FB;" FontFamily="{ThemeResource SymbolThemeFontFamily}" FontSize="16" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Style="{StaticResource DateTimePickerFlyoutButtonStyle}" Margin="0,2,0,0" />
                                <Button x:Name="DismissButton" Grid.Column="1" Content="&#xE711;" FontFamily="{ThemeResource SymbolThemeFontFamily}" FontSize="16" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Style="{StaticResource DateTimePickerFlyoutButtonStyle}" Margin="0,2,0,0" />
                            </Grid>
                        </Grid>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

And you have to set datacontext of Timepicker to your viewmodel.

   <TimePicker x:Name="TestTimePicker" Time="{Binding SelectedTime,Mode=TwoWay}" ClockIdentifier="12HourClock" Time="0" TimeChanged="TestTimePicker_TimeChanged" >
     </TimePicker>

    public MainPage()
            {
                this.InitializeComponent();
                DataContext = new TestViewModel();
                TestTimePicker.DataContext = this.DataContext;
            }

    public class TestViewModel:INotifyPropertyChanged
        {
            public DelegateCommand<TappedRoutedEventArgs> ClosePopUp { get; set; }
 TimeSpan selectedTime;
        public TimeSpan SelectedTime
        { get { return selectedTime; }
            set
            {
                if (value != selectedTime)
                {
                    selectedTime = value;
                    OnPropertyChanged("SelectedTime");
                }
            }
        }

            public TestViewModel()
        {

            ClosePopUp = new DelegateCommand<TappedRoutedEventArgs>((args) =>
            {
                if (args.OriginalSource is Grid)
                {
                    Grid grid = args.OriginalSource as Grid;
                    if (grid != null)
                    {
                       var fly = FlyoutBase.GetAttachedFlyout(grid);
                        var flyoutpresenter = FindParent<TimePickerFlyoutPresenter>(grid);
                        if (flyoutpresenter != null)
                            (flyoutpresenter.Parent as Popup).IsOpen = false;
                       var firstPicker= FindParent(grid,"FirstPickerHost");
                        var secondPicker = FindParent(grid, "SecondPickerHost");
                        var thirdPicker = FindParent(grid, "ThirdPickerHost");
                        var textblock = FindElementInVisualTree<TextBlock>(grid);
                        if (firstPicker != null)
                        {
                            SelectedTime = new TimeSpan(int.Parse(textblock.Text), SelectedTime.Minutes, SelectedTime.Seconds);

                        }
                         if(secondPicker!=null)
                        {
                            SelectedTime = new TimeSpan(SelectedTime.Hours, int.Parse(textblock.Text), SelectedTime.Seconds);
                        }
                        if (thirdPicker != null)
                        {
                          // AM/PM
                        }

                    }
                }
                else if(args.OriginalSource is TextBlock)
                {
                    TextBlock textblock = args.OriginalSource as TextBlock;
                    if (textblock != null)
                    {
                        var fly = FlyoutBase.GetAttachedFlyout(textblock);
                        var flyoutpresenter = FindParent<TimePickerFlyoutPresenter>(textblock);
                        if (flyoutpresenter != null)
                            (flyoutpresenter.Parent as Popup).IsOpen = false;
                        var firstPicker = FindParent(textblock, "FirstPickerHost");
                        var secondPicker = FindParent(textblock, "SecondPickerHost");
                        var thirdPicker = FindParent(textblock, "ThirdPickerHost");

                        if (firstPicker != null)
                        {
                            SelectedTime = new TimeSpan(int.Parse(textblock.Text), SelectedTime.Minutes, SelectedTime.Seconds);

                        }
                        if (secondPicker != null)
                        {
                            SelectedTime = new TimeSpan(SelectedTime.Hours, int.Parse(textblock.Text), SelectedTime.Seconds);
                        }
                        if (thirdPicker != null)
                        {
                           //  AM/PM
                        }
                    }
                }
                else
                {

                }
            });

        }

        public event PropertyChangedEventHandler PropertyChanged;
        void OnPropertyChanged(string propertyName)
        {
            // the new Null-conditional Operators are thread-safe:
            this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }

        private T FindParent<T>(DependencyObject child) where T : DependencyObject
        {
            var parent = VisualTreeHelper.GetParent(child);
            if (parent != null && parent is T)
                return (T)parent;
            else if (parent == null)
                return null;
            else
            {
                var result = FindParent<T>(parent);
                if (result != null)
                    return result;

            }
            return null;
        }
        private DependencyObject FindParent(DependencyObject child,string parentName) 
        {
            var parent = VisualTreeHelper.GetParent(child);
            if (parent != null && (parent as FrameworkElement).Name.Equals(parentName))
                return parent;
            else if (parent == null)
                return null;
            else
            {
                var result = FindParent(parent,parentName);
                if (result != null)
                    return result;

            }
            return null;
        }
       private T FindElementInVisualTree<T>(DependencyObject parentElement) where T : DependencyObject
    {
        var count = VisualTreeHelper.GetChildrenCount(parentElement);
        if (count == 0) return null;

        for (int i = 0; i < count; i++)
        {
            var child = VisualTreeHelper.GetChild(parentElement, i);
            if (child != null && child is T)
                return (T)child;
            else
            {
                var result = FindElementInVisualTree<T>(child);
                if (result != null)
                    return result;
            }
        }
        return null;
    }
    }

What i'm doing above in ClosePopUp command is programmatically finding TimePickerFlyoutPresenter using VisualTreeHelper getparaent() method TimePickerFlyoutPresenter parent is a PopUp that is actually your TimePickerFlyout. Set popup's IsOpen to false

// Updated the code to reflect selected hour and minute in timepicker. One issue left is update the selected AM or PM. I ll update if i get the solution

Here is a link to complete project which solves all issues Source Code

Community
  • 1
  • 1
Archana
  • 3,213
  • 1
  • 15
  • 21
  • Dear plz check this error https://onedrive.live.com/redir?resid=3DC2CE947157A15D!67918&authkey=!AG9x4eHFjMUEAYI&v=3&ithint=photo%2cpng – Zia Ur Rahman May 05 '16 at 19:21
  • @ZiaUrRahman Add template10 to your project. If you don't want to, then implement command. – Archana May 06 '16 at 04:51
  • Great! the Template10 removed the Delegate error, but var textblock = FindElementInVisualTree(grid); this line give error (the name FindElementInVisualTree<> doesnot exist in the current context). see the pic. https://onedrive.live.com/redir?resid=3DC2CE947157A15D!67919&authkey=!AHaeB0f72ASv_8k&v=3&ithint=photo%2cpng – Zia Ur Rahman May 06 '16 at 05:31
  • Ok. I'll add that method – Archana May 06 '16 at 05:40
  • I shared the link to complete project,which solves almost all issues. Happy coding :) – Archana May 06 '16 at 05:51
  • Thanks you so much, it worked perfect. Before your current update, I worked around & got the solution like this. string getTxt = ""; foreach (var gr in grid.Children) { if (gr is ContentPresenter) { var cp = (gr as ContentPresenter).Content as DatePickerFlyoutItem; getTxt = cp.PrimaryText; } } And removed the FindElementInVisualTree portion, and just assign the getTxt to SelectedTime's TimeSpan. Tnx again – Zia Ur Rahman May 06 '16 at 06:26
  • But assigning Selected AM/PM was difficult. Dont know how they are binding – Archana May 06 '16 at 06:29
  • Yes, I see the issue, InshaAllah will get the solution soon. – Zia Ur Rahman May 06 '16 at 06:34
  • I fixed it. Check the project which i shared – Archana May 06 '16 at 06:36
  • OK thank you, the project is being downloaded, so will check it right now. – Zia Ur Rahman May 06 '16 at 06:50
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/111188/discussion-between-zia-ur-rahman-and-lovetocode). – Zia Ur Rahman May 06 '16 at 06:50
  • Why the periodTextBlock always null and the count always 0. See the Pic. https://onedrive.live.com/redir?resid=3DC2CE947157A15D!67939&authkey=!AMdNKCuz4ZmT7CE&v=3&ithint=photo%2cpng Your project is running fine, but in my Project it is always return 0 and it button null. Why? – Zia Ur Rahman May 06 '16 at 09:49
  • Are you getting Sender object properly? – Archana May 06 '16 at 09:55
  • 1
    Oh! OK got it, actually the timepicker grid was collapsed (u can see in pic) and the actual height and width became 0, so the count was 0, but now I made it visible and it worked. Thanks Archana (hope this is ur actual name :)) ... you did an awesome job, this is infact a great work for UWP user because the 2 buttons inside time/date picker make no sense, it should behave like the iOS picker control, and you did it today ... Your nick name "LoveToCode" is really suit you. Thank you so much... And if possible plz give me ur skype ID. Soon I will post some other questions, and will contact you. – Zia Ur Rahman May 06 '16 at 10:10
  • Thanks. That's means a lot to me. You can always post questions here. Moreover I ll be active in this site. And there are many people who are willing to help you. – Archana May 06 '16 at 13:44
  • Yes, OK, No worries ... I will post questions here. thanks. :) – Zia Ur Rahman May 06 '16 at 15:56