5 changed files with 295 additions and 1 deletions
@ -0,0 +1,196 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using System.Text; |
||||
|
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 Microsoft.Windows.Controls |
||||
|
{ |
||||
|
public class DateTimePicker : Control |
||||
|
{ |
||||
|
#region Members
|
||||
|
|
||||
|
private Calendar _calendar; |
||||
|
|
||||
|
#endregion //Members
|
||||
|
|
||||
|
#region Properties
|
||||
|
|
||||
|
#region Format
|
||||
|
|
||||
|
public static readonly DependencyProperty FormatProperty = DependencyProperty.Register("Format", typeof(DateTimeFormat), typeof(DateTimePicker), new UIPropertyMetadata(DateTimeFormat.FullDateTime, OnFormatChanged)); |
||||
|
public DateTimeFormat Format |
||||
|
{ |
||||
|
get { return (DateTimeFormat)GetValue(FormatProperty); } |
||||
|
set { SetValue(FormatProperty, value); } |
||||
|
} |
||||
|
|
||||
|
private static void OnFormatChanged(DependencyObject o, DependencyPropertyChangedEventArgs e) |
||||
|
{ |
||||
|
DateTimePicker DateTimePicker = o as DateTimePicker; |
||||
|
if (DateTimePicker != null) |
||||
|
DateTimePicker.OnFormatChanged((DateTimeFormat)e.OldValue, (DateTimeFormat)e.NewValue); |
||||
|
} |
||||
|
|
||||
|
protected virtual void OnFormatChanged(DateTimeFormat oldValue, DateTimeFormat newValue) |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
|
||||
|
#endregion //Format
|
||||
|
|
||||
|
#region FormatString
|
||||
|
|
||||
|
public static readonly DependencyProperty FormatStringProperty = DependencyProperty.Register("FormatString", typeof(string), typeof(DateTimePicker), new UIPropertyMetadata(default(String), OnFormatStringChanged)); |
||||
|
public string FormatString |
||||
|
{ |
||||
|
get { return (string)GetValue(FormatStringProperty); } |
||||
|
set { SetValue(FormatStringProperty, value); } |
||||
|
} |
||||
|
|
||||
|
private static void OnFormatStringChanged(DependencyObject o, DependencyPropertyChangedEventArgs e) |
||||
|
{ |
||||
|
DateTimePicker DateTimePicker = o as DateTimePicker; |
||||
|
if (DateTimePicker != null) |
||||
|
DateTimePicker.OnFormatStringChanged((string)e.OldValue, (string)e.NewValue); |
||||
|
} |
||||
|
|
||||
|
protected virtual void OnFormatStringChanged(string oldValue, string newValue) |
||||
|
{ |
||||
|
if (string.IsNullOrEmpty(newValue)) |
||||
|
throw new ArgumentException("CustomFormat should be specified.", FormatString); |
||||
|
} |
||||
|
|
||||
|
#endregion //FormatString
|
||||
|
|
||||
|
#region IsOpen
|
||||
|
|
||||
|
public static readonly DependencyProperty IsOpenProperty = DependencyProperty.Register("IsOpen", typeof(bool), typeof(DateTimePicker), new UIPropertyMetadata(false)); |
||||
|
public bool IsOpen |
||||
|
{ |
||||
|
get { return (bool)GetValue(IsOpenProperty); } |
||||
|
set { SetValue(IsOpenProperty, value); } |
||||
|
} |
||||
|
|
||||
|
#endregion //IsOpen
|
||||
|
|
||||
|
#region SelectedDate
|
||||
|
|
||||
|
public static readonly DependencyProperty SelectedDateProperty = DependencyProperty.Register("SelectedDate", typeof(DateTime?), typeof(DateTimePicker), new UIPropertyMetadata(DateTime.Now, new PropertyChangedCallback(OnSelectedDateChanged), new CoerceValueCallback(OnCoerceSelectedDate))); |
||||
|
public DateTime? SelectedDate |
||||
|
{ |
||||
|
get { return (DateTime?)GetValue(SelectedDateProperty); } |
||||
|
set { SetValue(SelectedDateProperty, value); } |
||||
|
} |
||||
|
|
||||
|
private static object OnCoerceSelectedDate(DependencyObject o, object value) |
||||
|
{ |
||||
|
DateTimePicker dateTimePicker = o as DateTimePicker; |
||||
|
if (dateTimePicker != null) |
||||
|
return dateTimePicker.OnCoerceSelectedDate((DateTime?)value); |
||||
|
else |
||||
|
return value; |
||||
|
} |
||||
|
|
||||
|
private static void OnSelectedDateChanged(DependencyObject o, DependencyPropertyChangedEventArgs e) |
||||
|
{ |
||||
|
DateTimePicker dateTimePicker = o as DateTimePicker; |
||||
|
if (dateTimePicker != null) |
||||
|
dateTimePicker.OnSelectedDateChanged((DateTime?)e.OldValue, (DateTime?)e.NewValue); |
||||
|
} |
||||
|
|
||||
|
protected virtual DateTime? OnCoerceSelectedDate(DateTime? value) |
||||
|
{ |
||||
|
// TODO: Keep the proposed value within the desired range.
|
||||
|
return value; |
||||
|
} |
||||
|
|
||||
|
protected virtual void OnSelectedDateChanged(DateTime? oldValue, DateTime? newValue) |
||||
|
{ |
||||
|
if (_calendar != null && _calendar.SelectedDate.Value != newValue.Value) |
||||
|
_calendar.SelectedDate = newValue; |
||||
|
} |
||||
|
|
||||
|
#endregion //SelectedDate
|
||||
|
|
||||
|
#endregion //Properties
|
||||
|
|
||||
|
#region Constructors
|
||||
|
|
||||
|
static DateTimePicker() |
||||
|
{ |
||||
|
DefaultStyleKeyProperty.OverrideMetadata(typeof(DateTimePicker), new FrameworkPropertyMetadata(typeof(DateTimePicker))); |
||||
|
} |
||||
|
|
||||
|
public DateTimePicker() |
||||
|
{ |
||||
|
Keyboard.AddKeyDownHandler(this, OnKeyDown); |
||||
|
Mouse.AddPreviewMouseDownOutsideCapturedElementHandler(this, OnMouseDownOutsideCapturedElement); |
||||
|
} |
||||
|
|
||||
|
#endregion //Constructors
|
||||
|
|
||||
|
#region Base Class Overrides
|
||||
|
|
||||
|
public override void OnApplyTemplate() |
||||
|
{ |
||||
|
base.OnApplyTemplate(); |
||||
|
|
||||
|
_calendar = (Calendar)GetTemplateChild("Part_Calendar"); |
||||
|
_calendar.SelectedDatesChanged += Calendar_SelectedDatesChanged; |
||||
|
_calendar.SelectedDate = SelectedDate; |
||||
|
} |
||||
|
|
||||
|
#endregion //Base Class Overrides
|
||||
|
|
||||
|
#region Event Handlers
|
||||
|
|
||||
|
private void OnKeyDown(object sender, KeyEventArgs e) |
||||
|
{ |
||||
|
switch (e.Key) |
||||
|
{ |
||||
|
case Key.Escape: |
||||
|
case Key.Tab: |
||||
|
{ |
||||
|
CloseDateTimePicker(); |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private void OnMouseDownOutsideCapturedElement(object sender, MouseButtonEventArgs e) |
||||
|
{ |
||||
|
CloseDateTimePicker(); |
||||
|
} |
||||
|
|
||||
|
void Calendar_SelectedDatesChanged(object sender, SelectionChangedEventArgs e) |
||||
|
{ |
||||
|
if (e.AddedItems.Count > 0) |
||||
|
{ |
||||
|
var newDate = (DateTime?)e.AddedItems[0]; |
||||
|
SelectedDate = newDate.Value; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
#endregion //Event Handlers
|
||||
|
|
||||
|
#region Methods
|
||||
|
|
||||
|
private void CloseDateTimePicker() |
||||
|
{ |
||||
|
if (IsOpen) |
||||
|
IsOpen = false; |
||||
|
ReleaseMouseCapture(); |
||||
|
} |
||||
|
|
||||
|
#endregion //Methods
|
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,91 @@ |
|||||
|
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" |
||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
||||
|
xmlns:local="clr-namespace:Microsoft.Windows.Controls" |
||||
|
xmlns:chrome="clr-namespace:Microsoft.Windows.Controls.Chromes" |
||||
|
xmlns:coreConverters="clr-namespace:Microsoft.Windows.Controls.Core.Converters"> |
||||
|
|
||||
|
<coreConverters:InverseBoolConverter x:Key="InverseBoolConverter" /> |
||||
|
|
||||
|
<LinearGradientBrush x:Key="PopupDarkBorderBrush" EndPoint="0.5,1" StartPoint="0.5,0"> |
||||
|
<GradientStop Color="#FFA3AEB9" Offset="0"/> |
||||
|
<GradientStop Color="#FF8399A9" Offset="0.375"/> |
||||
|
<GradientStop Color="#FF718597" Offset="0.375"/> |
||||
|
<GradientStop Color="#FF617584" Offset="1"/> |
||||
|
</LinearGradientBrush> |
||||
|
|
||||
|
<LinearGradientBrush x:Key="PopupBackgroundBrush" StartPoint="0,0" EndPoint="0,1"> |
||||
|
<LinearGradientBrush.GradientStops> |
||||
|
<GradientStopCollection> |
||||
|
<GradientStop Offset="0" Color="#FFffffff"/> |
||||
|
<GradientStop Offset="1" Color="#FFE8EBED"/> |
||||
|
</GradientStopCollection> |
||||
|
</LinearGradientBrush.GradientStops> |
||||
|
</LinearGradientBrush> |
||||
|
|
||||
|
<Style x:Key="DateTimePickerToggleButtonStyle" TargetType="ToggleButton"> |
||||
|
<Setter Property="Template"> |
||||
|
<Setter.Value> |
||||
|
<ControlTemplate TargetType="ToggleButton"> |
||||
|
<Grid SnapsToDevicePixels="True"> |
||||
|
<chrome:ButtonChrome x:Name="ToggleButtonChrome" |
||||
|
CornerRadius="0,2.75,2.75,0" |
||||
|
RenderMouseOver="{TemplateBinding IsMouseOver}" |
||||
|
RenderPressed="{TemplateBinding IsPressed}" /> |
||||
|
|
||||
|
<Grid> |
||||
|
<Grid.ColumnDefinitions> |
||||
|
<ColumnDefinition Width="*"/> |
||||
|
<ColumnDefinition Width="Auto"/> |
||||
|
</Grid.ColumnDefinitions> |
||||
|
|
||||
|
<ContentPresenter HorizontalAlignment="Stretch" VerticalAlignment="Stretch" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" /> |
||||
|
|
||||
|
<Grid x:Name="arrowGlyph" IsHitTestVisible="False" Grid.Column="1" Margin="5"> |
||||
|
<Path Width="7" Height="4" Data="M 0,1 C0,1 0,0 0,0 0,0 3,0 3,0 3,0 3,1 3,1 3,1 4,1 4,1 4,1 4,0 4,0 4,0 7,0 7,0 7,0 7,1 7,1 7,1 6,1 6,1 6,1 6,2 6,2 6,2 5,2 5,2 5,2 5,3 5,3 5,3 4,3 4,3 4,3 4,4 4,4 4,4 3,4 3,4 3,4 3,3 3,3 3,3 2,3 2,3 2,3 2,2 2,2 2,2 1,2 1,2 1,2 1,1 1,1 1,1 0,1 0,1 z" Fill="#FF000000"/> |
||||
|
</Grid> |
||||
|
</Grid> |
||||
|
</Grid> |
||||
|
</ControlTemplate> |
||||
|
</Setter.Value> |
||||
|
</Setter> |
||||
|
</Style> |
||||
|
|
||||
|
<!-- =============================================================================== --> |
||||
|
<!-- DateTimePicker --> |
||||
|
<!-- =============================================================================== --> |
||||
|
|
||||
|
<Style TargetType="{x:Type local:DateTimePicker}"> |
||||
|
<Setter Property="Template"> |
||||
|
<Setter.Value> |
||||
|
<ControlTemplate TargetType="{x:Type local:DateTimePicker}"> |
||||
|
<Border> |
||||
|
<Grid> |
||||
|
<Grid> |
||||
|
<Grid.ColumnDefinitions> |
||||
|
<ColumnDefinition Width="*" /> |
||||
|
<ColumnDefinition Width="Auto" /> |
||||
|
</Grid.ColumnDefinitions> |
||||
|
<local:DateTimeUpDown BorderThickness="1,1,0,1" Format="{TemplateBinding Format}" FormatString="{TemplateBinding FormatString}" |
||||
|
Value="{Binding SelectedDate, RelativeSource={RelativeSource TemplatedParent}}" /> |
||||
|
<ToggleButton x:Name="_calendarToggleButton" Grid.Column="1" |
||||
|
IsChecked="{Binding IsOpen, RelativeSource={RelativeSource TemplatedParent}}" |
||||
|
Style="{StaticResource DateTimePickerToggleButtonStyle}" |
||||
|
IsHitTestVisible="{Binding IsOpen, RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource InverseBoolConverter}}"/> |
||||
|
</Grid> |
||||
|
<Popup IsOpen="{Binding IsChecked, ElementName=_calendarToggleButton}" StaysOpen="False"> |
||||
|
<Border BorderThickness="1" Background="{StaticResource PopupBackgroundBrush}" BorderBrush="{StaticResource PopupDarkBorderBrush}" Padding="3"> |
||||
|
<StackPanel> |
||||
|
<Calendar x:Name="Part_Calendar" |
||||
|
DisplayDate="{Binding SelectedDate, RelativeSource={RelativeSource TemplatedParent}, Mode=OneWay}"/> |
||||
|
<local:DateTimeUpDown x:Name="Part_TimeUpDown" Format="ShortTime" Value="{Binding SelectedDate, RelativeSource={RelativeSource TemplatedParent}}" Background="White" /> |
||||
|
</StackPanel> |
||||
|
</Border> |
||||
|
</Popup> |
||||
|
</Grid> |
||||
|
</Border> |
||||
|
</ControlTemplate> |
||||
|
</Setter.Value> |
||||
|
</Setter> |
||||
|
</Style> |
||||
|
|
||||
|
</ResourceDictionary> |
||||
Loading…
Reference in new issue