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.
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="" 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="" 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