I've created a UserControl
that should act as a control inside a Window
:
XAML:
<UserControl x:Class="MyApplication.UserControls.DateTimePicker"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:converters="clr-namespace:MyApplication.Converters"
x:Name="dtp">
<UserControl.Resources>
<converters:NullDateTimeConverter x:Key="nullDateTimeConverter" />
</UserControl.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="AUTO" />
</Grid.ColumnDefinitions>
<TextBox HorizontalAlignment="Stretch"
IsReadOnly="True"
Text="{Binding Path=SelectedDateTime,
ElementName=dtp,
Converter={StaticResource nullDateTimeConverter},
StringFormat={}{0:MM/dd/yyyy HH:mm},
UpdateSourceTrigger=PropertyChanged}" />
<Button Grid.Row="0"
Grid.Column="1"
Width="50"
BorderBrush="Orange"
BorderThickness="1"
Command="{Binding ChangePopupStatusCommand}"
Style="{DynamicResource SquareButtonStyle}">
<Rectangle Width="20"
Height="20"
Fill="{Binding RelativeSource={RelativeSource AncestorType=Button},
Path=Foreground}">
<Rectangle.OpacityMask>
<VisualBrush Stretch="Fill" Visual="{StaticResource appbar_calendar}" />
</Rectangle.OpacityMask>
</Rectangle>
</Button>
<Popup Grid.Row="1"
Grid.Column="0"
Width="400"
IsOpen="{Binding IsPopupOpen}"
PopupAnimation="Slide">
<DockPanel LastChildFill="True">
<Grid DockPanel.Dock="Top">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="2*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<RepeatButton Command="{Binding ChangeTimeCommand}"
CommandParameter="addHour"
Content="+" />
<RepeatButton Grid.Column="1"
Command="{Binding ChangeTimeCommand}"
CommandParameter="addMinute"
Content="+" />
<TextBox
Grid.Row="1"
Grid.ColumnSpan="2"
HorizontalContentAlignment="Center"
VerticalContentAlignment="Center">
<TextBox.Text>
<MultiBinding StringFormat=" {0:D2}:{1:D2}">
<Binding Mode="OneWay" Path="SelectedDateTime.Hour" />
<Binding Mode="OneWay" Path="SelectedDateTime.Minute" />
</MultiBinding>
</TextBox.Text>
</TextBox>
<RepeatButton Grid.Row="2"
Command="{Binding ChangeTimeCommand}"
CommandParameter="subHour"
Content="-" />
<!-- Click="SubHours_Click" -->
<RepeatButton Grid.Row="2"
Grid.Column="1"
Command="{Binding ChangeTimeCommand}"
CommandParameter="subMinute"
Content="-" />
</Grid>
<Calendar DockPanel.Dock="Bottom"
SelectedDate="{Binding SelectedDateTime,
ElementName=dtp,
Converter={StaticResource nullDateTimeConverter}}"
Style="{StaticResource styleCalendar}" />
</DockPanel>
</Popup>
</Grid>
</UserControl>
XAML.CS
public partial class DateTimePicker : UserControl, INotifyPropertyChanged
{
public DateTimePicker()
{
InitializeComponent();
(Content as FrameworkElement).DataContext = this;
}
#region SelectedTime
public DateTime? SelectedDateTime
{
get
{
return (DateTime?)GetValue(SelectedDateTimeProperty);
}
set
{
SetValue(SelectedDateTimeProperty, value);
}
}
public static readonly DependencyProperty
SelectedDateTimeProperty =
DependencyProperty.Register("SelectedDateTime",
typeof(DateTime?),
typeof(DateTimePicker));
#endregion
private bool _isPopupOpen;
public bool IsPopupOpen
{
get { return _isPopupOpen; }
set
{
SetProperty(ref _isPopupOpen, value);
}
}
#region INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged = delegate { };
protected virtual void SetProperty<T>(ref T member, T val,
[CallerMemberName]string propertyName = null)
{
if (object.Equals(member, val)) return;
member = val;
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
#endregion INotifyPropertyChanged
#region ChangePopup Command
private CommandBase _changePopupStatusCommand;
public CommandBase ChangePopupStatusCommand
{
get { return _changePopupStatusCommand ?? (_changePopupStatusCommand = new CommandBase(ChangePopupStatus)); }
}
private void ChangePopupStatus(object obj)
{
IsPopupOpen = !IsPopupOpen;
}
#endregion
#region ChangeTime Command
private CommandBase _chageTimeCommand;
public CommandBase ChangeTimeCommand
{
get { return _chageTimeCommand ?? (_chageTimeCommand = new CommandBase(ChangeTime)); }
}
private void ChangeTime(object obj)
{
if (!SelectedDateTime.HasValue)
SelectedDateTime = DateTime.Now;
switch (obj.ToString())
{
case "addHour":
SelectedDateTime = SelectedDateTime.Value.AddHours(1);
break;
case "addMinute":
SelectedDateTime = SelectedDateTime.Value.AddMinutes(1);
break;
case "subHour":
SelectedDateTime = SelectedDateTime.Value.AddHours(-1);
break;
case "subMinute":
SelectedDateTime = SelectedDateTime.Value.AddMinutes(-1);
break;
}
}
#endregion
}
NullDateTimeConverter
:
public class NullDateTimeConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
var val = (Nullable<DateTime>)value;
if (val.HasValue && val.Value > DateTime.MinValue)
return val;
return String.Empty;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
string strValue = value.ToString();
DateTime resultDateTime;
return DateTime.TryParse(strValue, out resultDateTime) ? resultDateTime : value;
}
}
Usage:
<DockPanel>
<TextBlock Text="Calibration Due" />
<uc:DateTimePicker SelectedDateTime="{Binding CalibarationDue,
Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged}" />
</DockPanel>
The thing I'm most unsure of is the way I use the binding
in side my picker. Any comments or suggestions?