Skip to content

Instantly share code, notes, and snippets.

@Apflkuacha
Forked from make4fun/DateTimePicker.xaml
Last active May 28, 2024 07:19
Show Gist options
  • Save Apflkuacha/406e755c8b42a70b7ab138e6b985bcdf to your computer and use it in GitHub Desktop.
Save Apflkuacha/406e755c8b42a70b7ab138e6b985bcdf to your computer and use it in GitHub Desktop.
C# DateTimePicker for WPF
<UserControl x:Class="Controls.DateTimePicker"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
mc:Ignorable="d">
<UserControl.Resources>
<ResourceDictionary>
<controls:InvertBoolConverter x:Key="InvertBoolConverter" />
</ResourceDictionary>
</UserControl.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<ToggleButton Grid.Column="0" MinHeight="25" MinWidth="25" Name="PopUpCalendarButton" IsChecked="False" IsHitTestVisible="{Binding IsOpen, ElementName=CalendarPopup, Mode=OneWay, Converter={StaticResource InvertBoolConverter}}">
<ToggleButton.Style>
<Style TargetType="{x:Type ToggleButton}">
<Setter Property="Background" Value="White" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ToggleButton}">
<Border Background="{TemplateBinding Background}" BorderBrush="Black" BorderThickness="1">
<ContentPresenter />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ToggleButton.Style>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="2*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBox BorderThickness="0" Height="26" x:Name="DateDisplay" VerticalAlignment="Center"
HorizontalAlignment="Left" VerticalContentAlignment="Center" HorizontalContentAlignment="Center"
IsHitTestVisible="False" IsReadOnly="True" IsUndoEnabled="False" />
<Image Grid.Column="1" Name="CalIco" Stretch="Fill" HorizontalAlignment="Right" />
</Grid>
</ToggleButton>
<Popup IsOpen="{Binding Path=IsChecked, ElementName=PopUpCalendarButton}" x:Name="CalendarPopup" PopupAnimation="Fade" StaysOpen="False" Width="180">
<Border Padding="2" Background="White">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="2*" />
<ColumnDefinition Width="2*" />
<ColumnDefinition Width="3*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Calendar Grid.ColumnSpan="3" Margin="0,-3,0,0" x:Name="CalDisplay" DisplayDateStart="{Binding Source={x:Static sys:DateTime.Today}, Mode=OneWay}" SelectedDate="{x:Static sys:DateTime.Now}" PreviewMouseUp="CalDisplay_PreviewMouseUp" />
<ComboBox Grid.Row="1" Grid.Column="0" Name="Hours" HorizontalContentAlignment="Right" VerticalContentAlignment="Center" SelectedIndex="8" SelectionChanged="Time_SelectionChanged">
<ComboBoxItem Content="6" />
<ComboBoxItem Content="7" />
<ComboBoxItem Content="8" />
<ComboBoxItem Content="9" />
<ComboBoxItem Content="10" />
<ComboBoxItem Content="11" />
<ComboBoxItem Content="12" />
<ComboBoxItem Content="13" />
<ComboBoxItem Content="14" />
<ComboBoxItem Content="15" />
<ComboBoxItem Content="16" />
<ComboBoxItem Content="17" />
<ComboBoxItem Content="18" />
</ComboBox>
<ComboBox Grid.Row="1" Grid.Column="1" Name="Min" HorizontalContentAlignment="Right" VerticalContentAlignment="Center" SelectedIndex="0" SelectionChanged="Time_SelectionChanged">
<ComboBoxItem Content="0" />
<ComboBoxItem Content="10" />
<ComboBoxItem Content="20" />
<ComboBoxItem Content="30" />
<ComboBoxItem Content="40" />
<ComboBoxItem Content="50" />
</ComboBox>
<Button Grid.Row="1" Grid.Column="2" Name="SaveTime" Content="OK" Click="SaveTime_Click" />
</Grid>
</Border>
</Popup>
</Grid>
</UserControl>
using System;
using System.Drawing;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Media.Imaging;
namespace Controls
{
/// Changes and improvements made =>
/// 1. Removed AM/PM chooser and made time selectable from 6:00 to 18:00
/// 2. Popup improvements
/// 3. Added SelectedDate DependencyProperty
///
/// Things that will be needed for this control to work properly (and look good :) ) =>
/// 1. A bitmap image 32x32 added as an embedded resource
///
/// Licensing =>
/// The Code Project Open License (CPOL)
/// http://www.codeproject.com/info/cpol10.aspx
public partial class DateTimePicker : UserControl
{
private const string DateTimeFormat = "dd.MM.yyyy HH:mm";
#region "Properties"
public DateTime SelectedDate
{
get => (DateTime)GetValue(SelectedDateProperty);
set => SetValue(SelectedDateProperty, value);
}
#endregion
#region "DependencyProperties"
public static readonly DependencyProperty SelectedDateProperty = DependencyProperty.Register("SelectedDate",
typeof(DateTime), typeof(DateTimePicker), new FrameworkPropertyMetadata(DateTime.Now, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
#endregion
public DateTimePicker()
{
InitializeComponent();
CalDisplay.SelectedDatesChanged += CalDisplay_SelectedDatesChanged;
CalDisplay.SelectedDate = DateTime.Now.AddDays(1);
BitmapSource ConvertGDI_To_WPF(Bitmap bm)
{
BitmapSource bms = null;
IntPtr h_bm = IntPtr.Zero;
h_bm = bm.GetHbitmap();
bms = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(h_bm, IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());
bms.Freeze();
h_bm = IntPtr.Zero;
return bms;
}
Bitmap bitmap1 = Properties.Resources.DateTimePicker;
bitmap1.MakeTransparent(Color.Black);
CalIco.Source = ConvertGDI_To_WPF(bitmap1);
}
#region "EventHandlers"
private void CalDisplay_SelectedDatesChanged(object sender, EventArgs e)
{
var hours = (Hours?.SelectedItem as ComboBoxItem)?.Content?.ToString() ?? "0";
var minutes = (Min?.SelectedItem as ComboBoxItem)?.Content?.ToString() ?? "0";
TimeSpan timeSpan = TimeSpan.Parse(hours + ":" + minutes);
if (CalDisplay.SelectedDate.Value.Date == DateTime.Today.Date && timeSpan.CompareTo(DateTime.Now.TimeOfDay) < 0)
{
timeSpan = TimeSpan.FromHours(DateTime.Now.Hour + 1);
}
var date = CalDisplay.SelectedDate.Value.Date + timeSpan;
DateDisplay.Text = date.ToString(DateTimeFormat);
SelectedDate = date;
}
private void SaveTime_Click(object sender, RoutedEventArgs e)
{
CalDisplay_SelectedDatesChanged(SaveTime, EventArgs.Empty);
PopUpCalendarButton.IsChecked = false;
}
private void Time_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
CalDisplay_SelectedDatesChanged(sender, e);
}
private void CalDisplay_PreviewMouseUp(object sender, MouseButtonEventArgs e)
{ // that it's not necessary to click twice after opening the calendar https://stackoverflow.com/q/6024372
if (Mouse.Captured is CalendarItem)
{
Mouse.Capture(null);
}
}
#endregion
}
[ValueConversion(typeof(bool), typeof(bool))]
public class InvertBoolConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (targetType != typeof(bool))
throw new InvalidOperationException("The target must be a boolean");
return !(bool)value;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (targetType != typeof(bool))
throw new InvalidOperationException("The target must be a boolean");
return !(bool)value;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment