Browse Source

Merge pull request #1367 from sdoroff/date-picker-control

DatePicker control
pull/1390/head
Steven Kirk 9 years ago
committed by GitHub
parent
commit
24f83fe3b8
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 6
      samples/ControlCatalog/ControlCatalog.csproj
  2. 3
      samples/ControlCatalog/MainView.xaml
  3. 46
      samples/ControlCatalog/Pages/DatePickerPage.xaml
  4. 36
      samples/ControlCatalog/Pages/DatePickerPage.xaml.cs
  5. 1188
      src/Avalonia.Controls/Calendar/DatePicker.cs
  6. 126
      src/Avalonia.Themes.Default/DatePicker.xaml
  7. 1
      src/Avalonia.Themes.Default/DefaultTheme.xaml
  8. 130
      tests/Avalonia.Controls.UnitTests/DatePickerTests.cs

6
samples/ControlCatalog/ControlCatalog.csproj

@ -60,6 +60,9 @@
<EmbeddedResource Include="Pages\DropDownPage.xaml">
<SubType>Designer</SubType>
</EmbeddedResource>
<EmbeddedResource Include="Pages\DatePickerPage.xaml">
<SubType>Designer</SubType>
</EmbeddedResource>
<EmbeddedResource Include="Pages\ExpanderPage.xaml">
<SubType>Designer</SubType>
</EmbeddedResource>
@ -128,6 +131,9 @@
<Compile Include="Pages\DropDownPage.xaml.cs">
<DependentUpon>DropDownPage.xaml</DependentUpon>
</Compile>
<Compile Include="Pages\DatePickerPage.xaml.cs">
<DependentUpon>DatePickerPage.xaml</DependentUpon>
</Compile>
<Compile Include="Pages\ExpanderPage.xaml.cs">
<DependentUpon>ExpanderPage.xaml</DependentUpon>
</Compile>

3
samples/ControlCatalog/MainView.xaml

@ -7,11 +7,12 @@
</TabControl.Transition>
<TabItem Header="Border"><pages:BorderPage/></TabItem>
<TabItem Header="Button"><pages:ButtonPage/></TabItem>
<TabItem Header="Calendar"><pages:CalendarPage/></TabItem>
<TabItem Header="Calendar"><pages:CalendarPage/></TabItem>
<TabItem Header="Canvas"><pages:CanvasPage/></TabItem>
<TabItem Header="Carousel"><pages:CarouselPage/></TabItem>
<TabItem Header="CheckBox"><pages:CheckBoxPage/></TabItem>
<TabItem Header="ContextMenu"><pages:ContextMenuPage/></TabItem>
<TabItem Header="DatePicker"><pages:DatePickerPage/></TabItem>
<TabItem Header="DropDown"><pages:DropDownPage/></TabItem>
<TabItem Header="Expander"><pages:ExpanderPage/></TabItem>
<TabItem Header="Image"><pages:ImagePage/></TabItem>

46
samples/ControlCatalog/Pages/DatePickerPage.xaml

@ -0,0 +1,46 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<StackPanel Orientation="Vertical" Gap="4">
<TextBlock Classes="h1">DatePicker</TextBlock>
<TextBlock Classes="h2">A control for selecting dates with a calendar drop-down</TextBlock>
<StackPanel Orientation="Horizontal"
Margin="0,16,0,0"
HorizontalAlignment="Center"
Gap="16">
<StackPanel Orientation="Vertical"
Width="200">
<TextBlock Text="SelectedDateFormat: Short"/>
<DatePicker Name="DatePicker1"
SelectedDateFormat="Short"
Margin="0,0,0,8"/>
<TextBlock Text="SelectedDateFormat: Long"/>
<DatePicker Name="DatePicker2"
SelectedDateFormat="Long"
Margin="0,0,0,8"/>
<TextBlock Text="SelectedDateFormat: Custom"/>
<DatePicker Name="DatePicker3"
SelectedDateFormat="Custom"
CustomDateFormatString="ddd, MMM d"
Margin="0,0,0,8"/>
<TextBlock Text="Blackout Dates"/>
<DatePicker Name="DatePicker4"
Margin="0,0,0,8"/>
<DatePicker Margin="0,0,0,8"
Watermark="Watermark"/>
<DatePicker Margin="0,0,0,8"
Name="DatePicker5"
Watermark="Floating Watermark"
UseFloatingWatermark="True"/>
<TextBlock Text="Disabled"/>
<DatePicker IsEnabled="False"/>
</StackPanel>
</StackPanel>
</StackPanel>
</UserControl>

36
samples/ControlCatalog/Pages/DatePickerPage.xaml.cs

@ -0,0 +1,36 @@
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using System;
namespace ControlCatalog.Pages
{
public class DatePickerPage : UserControl
{
public DatePickerPage()
{
InitializeComponent();
var dp1 = this.FindControl<DatePicker>("DatePicker1");
var dp2 = this.FindControl<DatePicker>("DatePicker2");
var dp3 = this.FindControl<DatePicker>("DatePicker3");
var dp4 = this.FindControl<DatePicker>("DatePicker4");
var dp5 = this.FindControl<DatePicker>("DatePicker5");
dp1.SelectedDate = DateTime.Today;
dp2.SelectedDate = DateTime.Today.AddDays(10);
dp3.SelectedDate = DateTime.Today.AddDays(20);
dp5.SelectedDate = DateTime.Today;
dp4.TemplateApplied += (s, e) =>
{
dp4.BlackoutDates.AddDatesInPast();
};
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
}
}

1188
src/Avalonia.Controls/Calendar/DatePicker.cs

File diff suppressed because it is too large

126
src/Avalonia.Themes.Default/DatePicker.xaml

@ -0,0 +1,126 @@
<!--
// (c) Copyright Microsoft Corporation.
// This source is subject to the Microsoft Public License (Ms-PL).
// Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
// All other rights reserved.
-->
<Styles xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style Selector="DatePicker">
<Setter Property="Background" Value="{DynamicResource ThemeBackgroundBrush}"/>
<Setter Property="BorderBrush" Value="{DynamicResource ThemeBorderMidBrush}"/>
<Setter Property="BorderThickness" Value="{DynamicResource ThemeBorderThickness}"/>
<Setter Property="Padding" Value="4"/>
<Setter Property="Template">
<ControlTemplate>
<Grid ColumnDefinitions="*,Auto">
<Grid.Styles>
<Style Selector="Button.CalendarDropDown">
<Setter Property="Template">
<ControlTemplate>
<Grid Height="18"
Width="19"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Margin="0"
Background="#FFFFFFFF"
ColumnDefinitions="*,*,*,*"
RowDefinitions="23*,19*,19*,19*"
ClipToBounds="False">
<Border Name="Highlight"
Margin="-1"
Grid.ColumnSpan="4"
Grid.Row="0"
Grid.RowSpan="4"
BorderThickness="1"
BorderBrush="{DynamicResource HighlightBrush}" />
<Border Name="Background"
Margin="0,-1,0,0"
Grid.ColumnSpan="4"
Grid.Row="1"
Grid.RowSpan="3"
BorderThickness="1"
BorderBrush="{DynamicResource ThemeBorderDarkBrush}"
CornerRadius=".5" />
<Rectangle Grid.ColumnSpan="4"
Grid.RowSpan="1"
StrokeThickness="1"
Stroke="{DynamicResource ThemeBorderDarkBrush}"
Fill="{DynamicResource ThemeAccentBrush}">
</Rectangle>
<Path HorizontalAlignment="Center"
Margin="4,3,4,3"
VerticalAlignment="Center"
RenderTransformOrigin="0.5,0.5"
Grid.Column="0"
Grid.Row="1"
Grid.ColumnSpan="4"
Grid.RowSpan="3"
Fill="{DynamicResource ThemeBorderDarkBrush}"
Stretch="Fill"
Data="M11.426758,8.4305077 L11.749023,8.4305077 L11.749023,16.331387 L10.674805,16.331387 L10.674805,10.299648 L9.0742188,11.298672 L9.0742188,10.294277 C9.4788408,10.090176 9.9094238,9.8090878 10.365967,9.4510155 C10.82251,9.0929432 11.176106,8.7527733 11.426758,8.4305077 z M14.65086,8.4305077 L18.566387,8.4305077 L18.566387,9.3435936 L15.671368,9.3435936 L15.671368,11.255703 C15.936341,11.058764 16.27293,10.960293 16.681133,10.960293 C17.411602,10.960293 17.969301,11.178717 18.354229,11.615566 C18.739157,12.052416 18.931622,12.673672 18.931622,13.479336 C18.931622,15.452317 18.052553,16.438808 16.294415,16.438808 C15.560365,16.438808 14.951641,16.234707 14.468243,15.826504 L14.881817,14.929531 C15.368796,15.326992 15.837872,15.525723 16.289043,15.525723 C17.298809,15.525723 17.803692,14.895514 17.803692,13.635098 C17.803692,12.460618 17.305971,11.873379 16.310528,11.873379 C15.83071,11.873379 15.399232,12.079271 15.016094,12.491055 L14.65086,12.238613 z" />
<Ellipse HorizontalAlignment="Center" VerticalAlignment="Center" Fill="#FFFFFFFF" StrokeThickness="0" Grid.ColumnSpan="4" Width="3" Height="3"/>
</Grid>
</ControlTemplate>
</Setter>
</Style>
<Style Selector="Button.CalendarDropDown /template/ Border#Highlight">
<Setter Property="IsVisible" Value="False"/>
</Style>
<Style Selector="Button.CalendarDropDown:pressed /template/ Border#Highlight">
<Setter Property="IsVisible" Value="True"/>
</Style>
<Style Selector="Button.CalendarDropDown:pointerover /template/ Border#Background">
<Setter Property="Background" Value="{DynamicResource ThemeAccentBrush4}"/>
</Style>
</Grid.Styles>
<TextBox Name="PART_TextBox"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Padding="{TemplateBinding Padding}"
Watermark="{TemplateBinding Watermark}"
UseFloatingWatermark="{TemplateBinding UseFloatingWatermark}"
DataValidationErrors.Errors="{TemplateBinding (DataValidationErrors.Errors)}"
Grid.Column="0"/>
<Button Name="PART_Button"
Grid.Column="1"
Width="20"
Classes="CalendarDropDown"
Foreground="{TemplateBinding Foreground}"
Background="#00FFFFFF"
BorderThickness="0"
Margin="2,0,2,0"
Padding="0"
ClipToBounds="False"
Focusable="False"/>
<Popup Name="PART_Popup"
PlacementTarget="{TemplateBinding}"
StaysOpen="False">
<Calendar Name="PART_Calendar"
FirstDayOfWeek="{TemplateBinding FirstDayOfWeek}"
IsTodayHighlighted="{TemplateBinding IsTodayHighlighted}"/>
</Popup>
</Grid>
</ControlTemplate>
</Setter>
</Style>
<Style Selector="DatePicker:focus /template/ TextBox#PART_TextBox">
<Setter Property="BorderBrush" Value="{DynamicResource ThemeBorderDarkBrush}"/>
</Style>
</Styles>

1
src/Avalonia.Themes.Default/DefaultTheme.xaml

@ -41,4 +41,5 @@
<StyleInclude Source="resm:Avalonia.Themes.Default.CalendarDayButton.xaml?assembly=Avalonia.Themes.Default"/>
<StyleInclude Source="resm:Avalonia.Themes.Default.CalendarItem.xaml?assembly=Avalonia.Themes.Default"/>
<StyleInclude Source="resm:Avalonia.Themes.Default.Calendar.xaml?assembly=Avalonia.Themes.Default"/>
<StyleInclude Source="resm:Avalonia.Themes.Default.DatePicker.xaml?assembly=Avalonia.Themes.Default"/>
</Styles>

130
tests/Avalonia.Controls.UnitTests/DatePickerTests.cs

@ -0,0 +1,130 @@
// Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using Avalonia.Controls.Primitives;
using Avalonia.Controls.Presenters;
using Avalonia.Controls.Templates;
using Avalonia.Data;
using Avalonia.Markup.Xaml.Data;
using Avalonia.Platform;
using Avalonia.UnitTests;
using Moq;
using Xunit;
namespace Avalonia.Controls.UnitTests
{
public class DatePickerTests
{
private static bool CompareDates(DateTime first, DateTime second)
{
return first.Year == second.Year &&
first.Month == second.Month &&
first.Day == second.Day;
}
[Fact]
public void SelectedDateChanged_Should_Fire_When_SelectedDate_Set()
{
using (UnitTestApplication.Start(Services))
{
bool handled = false;
DatePicker datePicker = CreateControl();
datePicker.SelectedDateChanged += (s,e) =>
{
handled = true;
};
DateTime value = new DateTime(2000, 10, 10);
datePicker.SelectedDate = value;
Threading.Dispatcher.UIThread.RunJobs();
Assert.True(handled);
}
}
[Fact]
public void Setting_Selected_Date_To_Blackout_Date_Should_Throw()
{
using (UnitTestApplication.Start(Services))
{
DatePicker datePicker = CreateControl();
datePicker.BlackoutDates.AddDatesInPast();
DateTime goodValue = DateTime.Today.AddDays(1);
datePicker.SelectedDate = goodValue;
Assert.True(CompareDates(datePicker.SelectedDate.Value, goodValue));
DateTime badValue = DateTime.Today.AddDays(-1);
Assert.ThrowsAny<ArgumentOutOfRangeException>(
() => datePicker.SelectedDate = badValue);
}
}
[Fact]
public void Adding_Blackout_Dates_Containing_Selected_Date_Should_Throw()
{
using (UnitTestApplication.Start(Services))
{
DatePicker datePicker = CreateControl();
datePicker.SelectedDate = DateTime.Today.AddDays(5);
Assert.ThrowsAny<ArgumentOutOfRangeException>(
() => datePicker.BlackoutDates.Add(new CalendarDateRange(DateTime.Today, DateTime.Today.AddDays(10))));
}
}
private static TestServices Services => TestServices.MockThreadingInterface.With(
standardCursorFactory: Mock.Of<IStandardCursorFactory>());
private DatePicker CreateControl()
{
var datePicker =
new DatePicker
{
Template = CreateTemplate()
};
datePicker.ApplyTemplate();
return datePicker;
}
private IControlTemplate CreateTemplate()
{
return new FuncControlTemplate<DatePicker>(control =>
{
var textBox =
new TextBox
{
Name = "PART_TextBox"
};
var button =
new Button
{
Name = "PART_Button"
};
var calendar =
new Calendar
{
Name = "PART_Calendar"
};
var popup =
new Popup
{
Name = "PART_Popup"
};
var panel = new Panel();
panel.Children.Add(textBox);
panel.Children.Add(button);
panel.Children.Add(popup);
panel.Children.Add(calendar);
return panel;
});
}
}
}
Loading…
Cancel
Save