Reputation: 992
I may be completely off on this, but I swear I remember reading somewhere how to do this, I just can't seem to find it. I have a DependencyProperty Minutes
as part of a TimePicker custom control. It's data type is int
, as it was the only way to get the increase/decrease button to work. The problem with this is that the minutes from 1-9 display without the leading zero. To circumvent this, I added a standard property MinuteZeros
, which converts the value of Minutes
to a string
and employs ToString("00")
. This property is bound to the display content. Now when I hit the increase/decrease buttons though, it doesn't update. How do I bind Minutes
and MinuteZeros
so that they update each other automatically?
Code:
public class TimePicker : Control
{
public static DependencyProperty HourProperty = DependencyProperty.Register("Hour", typeof(int), typeof(TimePicker),
new FrameworkPropertyMetadata((int)12, new PropertyChangedCallback(OnHourChanged)));
public static DependencyProperty MinuteProperty = DependencyProperty.Register("Minute", typeof(int), typeof(TimePicker),
new FrameworkPropertyMetadata((int)00, new PropertyChangedCallback(OnMinuteChanged)));
public int Hour
{
get { return (int)GetValue(HourProperty); }
set { SetValue(HourProperty, value); }
}
public string MinuteZeros
{
get { return Minute.ToString("00"); }
set { value = Minute.ToString("00"); }
}
public int Minute
{
get { return (int)GetValue(MinuteProperty); }
set { SetValue(MinuteProperty, value); }
}
#endregion
#region Events
public override void OnApplyTemplate()
{
var upButton = GetTemplateChild("PART_IncreaseTime") as RepeatButton;
upButton.Click += IncreaseClick;
var downButton = GetTemplateChild("PART_DecreaseTime") as RepeatButton;
downButton.Click += DecreaseClick;
var hourButton = GetTemplateChild("PART_Hour") as ToggleButton;
hourButton.Checked += HourSelected;
var minuteButton = GetTemplateChild("PART_Minute") as ToggleButton;
minuteButton.Checked += MinuteSelected;
}
private void HourSelected(object sender, RoutedEventArgs e)
{
var minuteButton = GetTemplateChild("PART_Minute") as ToggleButton;
minuteButton.IsChecked = false;
}
private void MinuteSelected(object sender, RoutedEventArgs e)
{
var hourButton = GetTemplateChild("PART_Hour") as ToggleButton;
hourButton.IsChecked = false;
}
private void IncreaseClick(object sender, RoutedEventArgs e)
{
var hourButton = GetTemplateChild("PART_Hour") as ToggleButton;
var minuteButton = GetTemplateChild("PART_Minute") as ToggleButton;
if (hourButton.IsChecked == true)
{
if (Hour == 12)
{
Hour = 1;
}
else
{
Hour += 1;
}
}
else if (minuteButton.IsChecked == true)
{
if (Minute == 59)
{
Minute = 00;
}
else
{
Minute += 1;
}
}
}
private void DecreaseClick(object sender, RoutedEventArgs e)
{
var hourButton = GetTemplateChild("PART_Hour") as ToggleButton;
var minuteButton = GetTemplateChild("PART_Minute") as ToggleButton;
if (hourButton.IsChecked == true)
{
if (Hour == 1)
{
Hour = 12;
}
else
{
Hour -= 1;
}
}
else if (minuteButton.IsChecked == true)
{
if (Minute == 00)
{
Minute = 59;
}
else
{
Minute -= 1;
}
}
}
private static void OnHourChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
}
private static void OnMinuteChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
}
static TimePicker()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(TimePicker), new FrameworkPropertyMetadata(typeof(TimePicker)));
}
}
public partial class TimePickerEvents : ResourceDictionary
{
TimePicker time = new TimePicker();
void PART_IncreaseTime_Click(object sender, RoutedEventArgs e)
{
time.Hour += 1;
}
}
XAML:
<ToggleButton x:Name="PART_Minute"
VerticalAlignment="{TemplateBinding VerticalAlignment}"
Margin="0"
MinWidth="25"
BorderBrush="Transparent"
Content="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=MinuteZeros}">
<ToggleButton.Template>
<ControlTemplate TargetType="{x:Type ToggleButton}">
<Grid>
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
<ContentPresenter x:Name="ContentPart"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
TextBlock.Foreground="#FF605c" Visibility="Collapsed">
<ContentPresenter.Effect>
<BlurEffect />
</ContentPresenter.Effect>
</ContentPresenter>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="ContentPart" Property="Visibility" Value="Visible" />
</Trigger>
<Trigger Property="IsChecked" Value="True">
<Setter Property="FontWeight" Value="Bold" />
<Setter TargetName="ContentPart" Property="Visibility" Value="Visible" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</ToggleButton.Template>
<ToggleButton.Style>
<Style TargetType="{x:Type ToggleButton}">
<Setter Property="Background" Value="Transparent" />
</Style>
</ToggleButton.Style>
</ToggleButton>
Upvotes: 0
Views: 205
Reputation: 992
Just wanted to post the final changes that made this work.
public static DependencyProperty SelectedTimeProperty = DependencyProperty.Register("SelectedTime", typeof(TimeSpan), typeof(TimePicker),
new FrameworkPropertyMetadata((TimeSpan.Zero), new PropertyChangedCallback(OnSelectedTimeChanged)));
public TimeSpan SelectedTime
{
get { return (TimeSpan)GetValue(SelectedTimeProperty); }
set { SetValue(SelectedTimeProperty, value); }
}
private static void OnHourChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
TimePicker tp = (TimePicker)sender;
//TimePicker tp = new TimePicker();
var amButton = tp.GetTemplateChild("PART_AmIndicator") as RadioButton;
var pmButton = tp.GetTemplateChild("PART_PmIndicator") as RadioButton;
if (pmButton.IsChecked != false)
{
tp.SelectedTime = new TimeSpan((int.Parse(tp.Hour) + 12), int.Parse(tp.Minute), 0);
}
else if (amButton.IsChecked != false && (tp.Hour == "12"))
{
tp.SelectedTime = new TimeSpan(0, int.Parse(tp.Minute), 0);
}
else
{
tp.SelectedTime = new TimeSpan(int.Parse(tp.Hour), int.Parse(tp.Minute), 0);
}
}
private static void OnMinuteChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
//TimePicker tp = new TimePicker();
TimePicker tp = (TimePicker)sender;
var amButton = tp.GetTemplateChild("PART_AmIndicator") as RadioButton;
var pmButton = tp.GetTemplateChild("PART_PmIndicator") as RadioButton;
if (pmButton.IsChecked != false)
{
tp.SelectedTime = new TimeSpan((int.Parse(tp.Hour) + 12), int.Parse(tp.Minute), 0);
}
else if (amButton.IsChecked != false && (tp.Hour == "12"))
{
tp.SelectedTime = new TimeSpan(0, int.Parse(tp.Minute), 0);
}
else
{
tp.SelectedTime = new TimeSpan(int.Parse(tp.Hour), int.Parse(tp.Minute), 0);
}
}
Upvotes: 0
Reputation: 42991
Option 1: use StringFormat - doesn't work, see SO article
Option 2: use a StringFormatConverter - which does work
Get rid of MinuteZeros and use
<Converters:StringFormatConverter x:Key="StringFormatConverter" />
{Binding
RelativeSource={RelativeSource TemplatedParent},
Path=Minutes,
StringFormatConverter={StaticResource StringFormatConverter},
ConverterParameter=D2
}
public class StringFormatConverter : IValueConverter
{
#region Implementation of IValueConverter
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value == null)
{
throw new ArgumentNullException("value");
}
var fmt = string.Format("{{0:{0}}}", parameter);
return string.Format(fmt, value);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
#endregion
}
Option 3: which I haven't implemented
Put logic in your OnHourChanged and OnMinuteChanged handlers to synchronize Minutes and MinutesZeros.
Upvotes: 1