committed by
GitHub
130 changed files with 7321 additions and 959 deletions
@ -1,5 +1,5 @@ |
|||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> |
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> |
||||
<ItemGroup> |
<ItemGroup> |
||||
<PackageReference Include="MonoMac.NetStandard" Version="0.0.3" /> |
<PackageReference Include="MonoMac.NetStandard" Version="0.0.4" /> |
||||
</ItemGroup> |
</ItemGroup> |
||||
</Project> |
</Project> |
||||
|
|||||
@ -1,5 +0,0 @@ |
|||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> |
|
||||
<ItemGroup> |
|
||||
<PackageReference Include="Serilog.Sinks.Trace" Version="2.1.0" /> |
|
||||
</ItemGroup> |
|
||||
</Project> |
|
||||
@ -1,5 +1,7 @@ |
|||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> |
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> |
||||
<ItemGroup> |
<ItemGroup> |
||||
<PackageReference Include="Serilog" Version="2.4.0" /> |
<PackageReference Include="Serilog" Version="2.5.0" /> |
||||
|
<PackageReference Include="Serilog.Sinks.Trace" Version="2.1.0" /> |
||||
|
<PackageReference Include="Serilog.Sinks.Debug" Version="1.0.0" /> |
||||
</ItemGroup> |
</ItemGroup> |
||||
</Project> |
</Project> |
||||
|
|||||
@ -1,5 +0,0 @@ |
|||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> |
|
||||
<ItemGroup> |
|
||||
<PackageReference Include="Splat" Version="2.0.0" /> |
|
||||
</ItemGroup> |
|
||||
</Project> |
|
||||
@ -0,0 +1,47 @@ |
|||||
|
<UserControl xmlns="https://github.com/avaloniaui" |
||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> |
||||
|
<StackPanel Orientation="Vertical" Gap="4"> |
||||
|
<TextBlock Classes="h1">Calendar</TextBlock> |
||||
|
<TextBlock Classes="h2">A calendar control for selecting dates</TextBlock> |
||||
|
|
||||
|
<StackPanel Orientation="Horizontal" |
||||
|
Margin="0,16,0,0" |
||||
|
HorizontalAlignment="Center" |
||||
|
Gap="16"> |
||||
|
<StackPanel Orientation="Vertical"> |
||||
|
<TextBlock Text="SelectionMode: None"/> |
||||
|
<Calendar SelectionMode="None" |
||||
|
Margin="0,0,0,8"/> |
||||
|
|
||||
|
<TextBlock Text="SelectionMode: SingleDate"/> |
||||
|
<Calendar SelectionMode="SingleDate" |
||||
|
Margin="0,0,0,8"/> |
||||
|
|
||||
|
<TextBlock Text="Disabled"/> |
||||
|
<Calendar IsEnabled="False" |
||||
|
SelectionMode="SingleDate"/> |
||||
|
</StackPanel> |
||||
|
|
||||
|
<StackPanel Orientation="Vertical"> |
||||
|
<TextBlock Text="SelectionMode: SingleRange"/> |
||||
|
<Calendar SelectionMode="SingleRange" |
||||
|
Margin="0,0,0,8"/> |
||||
|
|
||||
|
<TextBlock Text="SelectionMode: MultipleRange"/> |
||||
|
<Calendar SelectionMode="MultipleRange"/> |
||||
|
</StackPanel> |
||||
|
|
||||
|
<StackPanel Orientation="Vertical"> |
||||
|
<TextBlock Text="DisplayDates"/> |
||||
|
<Calendar Name="DisplayDatesCalendar" |
||||
|
SelectionMode="SingleDate" |
||||
|
Margin="0,0,0,8"/> |
||||
|
|
||||
|
<TextBlock Text="BlackoutDates"/> |
||||
|
<Calendar Name="BlackoutDatesCalendar" |
||||
|
SelectionMode="SingleDate" /> |
||||
|
</StackPanel> |
||||
|
|
||||
|
</StackPanel> |
||||
|
</StackPanel> |
||||
|
</UserControl> |
||||
@ -0,0 +1,28 @@ |
|||||
|
using Avalonia.Controls; |
||||
|
using Avalonia.Markup.Xaml; |
||||
|
using System; |
||||
|
|
||||
|
namespace ControlCatalog.Pages |
||||
|
{ |
||||
|
public class CalendarPage : UserControl |
||||
|
{ |
||||
|
public CalendarPage() |
||||
|
{ |
||||
|
this.InitializeComponent(); |
||||
|
|
||||
|
var today = DateTime.Today; |
||||
|
var cal1 = this.FindControl<Calendar>("DisplayDatesCalendar"); |
||||
|
cal1.DisplayDateStart = today.AddDays(-25); |
||||
|
cal1.DisplayDateEnd = today.AddDays(25); |
||||
|
|
||||
|
var cal2 = this.FindControl<Calendar>("BlackoutDatesCalendar"); |
||||
|
cal2.BlackoutDates.AddDatesInPast(); |
||||
|
cal2.BlackoutDates.Add(new CalendarDateRange(today.AddDays(6))); |
||||
|
} |
||||
|
|
||||
|
private void InitializeComponent() |
||||
|
{ |
||||
|
AvaloniaXamlLoader.Load(this); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -1,15 +1,28 @@ |
|||||
<UserControl xmlns="https://github.com/avaloniaui"> |
<UserControl xmlns="https://github.com/avaloniaui" |
||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> |
||||
<StackPanel Orientation="Vertical" Gap="4"> |
<StackPanel Orientation="Vertical" Gap="4"> |
||||
<TextBlock Classes="h1">CheckBox</TextBlock> |
<TextBlock Classes="h1">CheckBox</TextBlock> |
||||
<TextBlock Classes="h2">A check box control</TextBlock> |
<TextBlock Classes="h2">A check box control</TextBlock> |
||||
|
|
||||
<StackPanel Orientation="Vertical" |
<StackPanel Orientation="Horizontal" |
||||
Margin="0,16,0,0" |
Margin="0,16,0,0" |
||||
HorizontalAlignment="Center" |
HorizontalAlignment="Center" |
||||
Gap="16"> |
Gap="16"> |
||||
<CheckBox>Unchecked</CheckBox> |
<StackPanel Orientation="Vertical" |
||||
<CheckBox IsChecked="True">Checked</CheckBox> |
Gap="16"> |
||||
<CheckBox IsChecked="True" IsEnabled="False">Disabled</CheckBox> |
<CheckBox>Unchecked</CheckBox> |
||||
</StackPanel> |
<CheckBox IsChecked="True">Checked</CheckBox> |
||||
|
<CheckBox IsChecked="{x:Null}">Indeterminate</CheckBox> |
||||
|
<CheckBox IsChecked="True" IsEnabled="False">Disabled</CheckBox> |
||||
|
</StackPanel> |
||||
|
<StackPanel Orientation="Vertical" |
||||
|
HorizontalAlignment="Center" |
||||
|
Gap="16"> |
||||
|
<CheckBox IsChecked="False" IsThreeState="True">Three State: Unchecked</CheckBox> |
||||
|
<CheckBox IsChecked="True" IsThreeState="True">Three State: Checked</CheckBox> |
||||
|
<CheckBox IsChecked="{x:Null}" IsThreeState="True">Three State: Indeterminate</CheckBox> |
||||
|
<CheckBox IsChecked="{x:Null}" IsThreeState="True" IsEnabled="False">Three State: Disabled</CheckBox> |
||||
|
</StackPanel> |
||||
|
</StackPanel> |
||||
</StackPanel> |
</StackPanel> |
||||
</UserControl> |
</UserControl> |
||||
@ -1,15 +1,27 @@ |
|||||
<UserControl xmlns="https://github.com/avaloniaui"> |
<UserControl xmlns="https://github.com/avaloniaui" |
||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> |
||||
<StackPanel Orientation="Vertical" Gap="4"> |
<StackPanel Orientation="Vertical" Gap="4"> |
||||
<TextBlock Classes="h1">RadioButton</TextBlock> |
<TextBlock Classes="h1">RadioButton</TextBlock> |
||||
<TextBlock Classes="h2">Allows the selection of a single option of many</TextBlock> |
<TextBlock Classes="h2">Allows the selection of a single option of many</TextBlock> |
||||
|
|
||||
<StackPanel Orientation="Vertical" |
<StackPanel Orientation="Horizontal" |
||||
Margin="0,16,0,0" |
Margin="0,16,0,0" |
||||
HorizontalAlignment="Center" |
HorizontalAlignment="Center" |
||||
Gap="16"> |
Gap="16"> |
||||
<RadioButton IsChecked="True">Option 1</RadioButton> |
<StackPanel Orientation="Vertical" |
||||
<RadioButton>Option 2</RadioButton> |
Gap="16"> |
||||
<RadioButton IsEnabled="False">Disabled</RadioButton> |
<RadioButton IsChecked="True">Option 1</RadioButton> |
||||
</StackPanel> |
<RadioButton>Option 2</RadioButton> |
||||
|
<RadioButton IsChecked="{x:Null}">Option 3</RadioButton> |
||||
|
<RadioButton IsEnabled="False">Disabled</RadioButton> |
||||
|
</StackPanel> |
||||
|
<StackPanel Orientation="Vertical" |
||||
|
Gap="16"> |
||||
|
<RadioButton IsChecked="True" IsThreeState="True">Three States: Option 1</RadioButton> |
||||
|
<RadioButton IsChecked="False" IsThreeState="True">Three States: Option 2</RadioButton> |
||||
|
<RadioButton IsChecked="{x:Null}" IsThreeState="True">Three States: Option 3</RadioButton> |
||||
|
<RadioButton IsChecked="{x:Null}" IsThreeState="True" IsEnabled="False">Disabled</RadioButton> |
||||
|
</StackPanel> |
||||
|
</StackPanel> |
||||
</StackPanel> |
</StackPanel> |
||||
</UserControl> |
</UserControl> |
||||
File diff suppressed because it is too large
@ -0,0 +1,215 @@ |
|||||
|
// (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.
|
||||
|
|
||||
|
using Avalonia.Threading; |
||||
|
using System; |
||||
|
using System.Collections.ObjectModel; |
||||
|
using System.Linq; |
||||
|
using System.Threading; |
||||
|
|
||||
|
namespace Avalonia.Controls.Primitives |
||||
|
{ |
||||
|
public sealed class CalendarBlackoutDatesCollection : ObservableCollection<CalendarDateRange> |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// The Calendar whose dates this object represents.
|
||||
|
/// </summary>
|
||||
|
private Calendar _owner; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Initializes a new instance of the
|
||||
|
/// <see cref="T:Avalonia.Controls.Primitives.CalendarBlackoutDatesCollection" />
|
||||
|
/// class.
|
||||
|
/// </summary>
|
||||
|
/// <param name="owner">
|
||||
|
/// The <see cref="T:Avalonia.Controls.Calendar" /> whose dates
|
||||
|
/// this object represents.
|
||||
|
/// </param>
|
||||
|
public CalendarBlackoutDatesCollection(Calendar owner) |
||||
|
{ |
||||
|
_owner = owner ?? throw new ArgumentNullException(nameof(owner)); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Adds all dates before <see cref="P:System.DateTime.Today" /> to the
|
||||
|
/// collection.
|
||||
|
/// </summary>
|
||||
|
public void AddDatesInPast() |
||||
|
{ |
||||
|
Add(new CalendarDateRange(DateTime.MinValue, DateTime.Today.AddDays(-1))); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Returns a value that represents whether this collection contains the
|
||||
|
/// specified date.
|
||||
|
/// </summary>
|
||||
|
/// <param name="date">The date to search for.</param>
|
||||
|
/// <returns>
|
||||
|
/// True if the collection contains the specified date; otherwise,
|
||||
|
/// false.
|
||||
|
/// </returns>
|
||||
|
public bool Contains(DateTime date) |
||||
|
{ |
||||
|
int count = Count; |
||||
|
for (int i = 0; i < count; i++) |
||||
|
{ |
||||
|
if (DateTimeHelper.InRange(date, this[i])) |
||||
|
{ |
||||
|
return true; |
||||
|
} |
||||
|
} |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Returns a value that represents whether this collection contains the
|
||||
|
/// specified range of dates.
|
||||
|
/// </summary>
|
||||
|
/// <param name="start">The start of the date range.</param>
|
||||
|
/// <param name="end">The end of the date range.</param>
|
||||
|
/// <returns>
|
||||
|
/// True if all dates in the range are contained in the collection;
|
||||
|
/// otherwise, false.
|
||||
|
/// </returns>
|
||||
|
public bool Contains(DateTime start, DateTime end) |
||||
|
{ |
||||
|
DateTime rangeStart; |
||||
|
DateTime rangeEnd; |
||||
|
|
||||
|
if (DateTime.Compare(end, start) > -1) |
||||
|
{ |
||||
|
rangeStart = DateTimeHelper.DiscardTime(start).Value; |
||||
|
rangeEnd = DateTimeHelper.DiscardTime(end).Value; |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
rangeStart = DateTimeHelper.DiscardTime(end).Value; |
||||
|
rangeEnd = DateTimeHelper.DiscardTime(start).Value; |
||||
|
} |
||||
|
|
||||
|
int count = Count; |
||||
|
for (int i = 0; i < count; i++) |
||||
|
{ |
||||
|
CalendarDateRange range = this[i]; |
||||
|
if (DateTime.Compare(range.Start, rangeStart) == 0 && DateTime.Compare(range.End, rangeEnd) == 0) |
||||
|
{ |
||||
|
return true; |
||||
|
} |
||||
|
} |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Returns a value that represents whether this collection contains any
|
||||
|
/// date in the specified range.
|
||||
|
/// </summary>
|
||||
|
/// <param name="range">The range of dates to search for.</param>
|
||||
|
/// <returns>
|
||||
|
/// True if any date in the range is contained in the collection;
|
||||
|
/// otherwise, false.
|
||||
|
/// </returns>
|
||||
|
public bool ContainsAny(CalendarDateRange range) |
||||
|
{ |
||||
|
return this.Any(r => r.ContainsAny(range)); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Removes all items from the collection.
|
||||
|
/// </summary>
|
||||
|
/// <remarks>
|
||||
|
/// This implementation raises the CollectionChanged event.
|
||||
|
/// </remarks>
|
||||
|
protected override void ClearItems() |
||||
|
{ |
||||
|
EnsureValidThread(); |
||||
|
|
||||
|
base.ClearItems(); |
||||
|
_owner.UpdateMonths(); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Inserts an item into the collection at the specified index.
|
||||
|
/// </summary>
|
||||
|
/// <param name="index">
|
||||
|
/// The zero-based index at which item should be inserted.
|
||||
|
/// </param>
|
||||
|
/// <param name="item">The object to insert.</param>
|
||||
|
/// <remarks>
|
||||
|
/// This implementation raises the CollectionChanged event.
|
||||
|
/// </remarks>
|
||||
|
protected override void InsertItem(int index, CalendarDateRange item) |
||||
|
{ |
||||
|
EnsureValidThread(); |
||||
|
|
||||
|
if (!IsValid(item)) |
||||
|
{ |
||||
|
throw new ArgumentOutOfRangeException("Value is not valid."); |
||||
|
} |
||||
|
|
||||
|
base.InsertItem(index, item); |
||||
|
_owner.UpdateMonths(); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Removes the item at the specified index of the collection.
|
||||
|
/// </summary>
|
||||
|
/// <param name="index">
|
||||
|
/// The zero-based index of the element to remove.
|
||||
|
/// </param>
|
||||
|
/// <remarks>
|
||||
|
/// This implementation raises the CollectionChanged event.
|
||||
|
/// </remarks>
|
||||
|
protected override void RemoveItem(int index) |
||||
|
{ |
||||
|
EnsureValidThread(); |
||||
|
|
||||
|
base.RemoveItem(index); |
||||
|
_owner.UpdateMonths(); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Replaces the element at the specified index.
|
||||
|
/// </summary>
|
||||
|
/// <param name="index">
|
||||
|
/// The zero-based index of the element to replace.
|
||||
|
/// </param>
|
||||
|
/// <param name="item">
|
||||
|
/// The new value for the element at the specified index.
|
||||
|
/// </param>
|
||||
|
/// <remarks>
|
||||
|
/// This implementation raises the CollectionChanged event.
|
||||
|
/// </remarks>
|
||||
|
protected override void SetItem(int index, CalendarDateRange item) |
||||
|
{ |
||||
|
EnsureValidThread(); |
||||
|
|
||||
|
if (!IsValid(item)) |
||||
|
{ |
||||
|
throw new ArgumentOutOfRangeException("Value is not valid."); |
||||
|
} |
||||
|
|
||||
|
base.SetItem(index, item); |
||||
|
_owner.UpdateMonths(); |
||||
|
} |
||||
|
|
||||
|
private bool IsValid(CalendarDateRange item) |
||||
|
{ |
||||
|
foreach (DateTime day in _owner.SelectedDates) |
||||
|
{ |
||||
|
if (DateTimeHelper.InRange(day, item)) |
||||
|
{ |
||||
|
return false; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
private void EnsureValidThread() |
||||
|
{ |
||||
|
Dispatcher.UIThread.VerifyAccess(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,193 @@ |
|||||
|
// (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.
|
||||
|
|
||||
|
using Avalonia.Input; |
||||
|
using System; |
||||
|
|
||||
|
namespace Avalonia.Controls.Primitives |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Represents a button on a
|
||||
|
/// <see cref="T:Avalonia.Controls.Calendar" />.
|
||||
|
/// </summary>
|
||||
|
public sealed class CalendarButton : Button |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// A value indicating whether the button is focused.
|
||||
|
/// </summary>
|
||||
|
private bool _isCalendarButtonFocused; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// A value indicating whether the button is inactive.
|
||||
|
/// </summary>
|
||||
|
private bool _isInactive; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// A value indicating whether the button is selected.
|
||||
|
/// </summary>
|
||||
|
private bool _isSelected; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Initializes a new instance of the
|
||||
|
/// <see cref="T:Avalonia.Controls.Primitives.CalendarButton" />
|
||||
|
/// class.
|
||||
|
/// </summary>
|
||||
|
public CalendarButton() |
||||
|
: base() |
||||
|
{ |
||||
|
Content = DateTimeHelper.GetCurrentDateFormat().AbbreviatedMonthNames[0]; |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets or sets the Calendar associated with this button.
|
||||
|
/// </summary>
|
||||
|
internal Calendar Owner { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets or sets a value indicating whether the button is focused.
|
||||
|
/// </summary>
|
||||
|
internal bool IsCalendarButtonFocused |
||||
|
{ |
||||
|
get { return _isCalendarButtonFocused; } |
||||
|
set |
||||
|
{ |
||||
|
if (_isCalendarButtonFocused != value) |
||||
|
{ |
||||
|
_isCalendarButtonFocused = value; |
||||
|
SetPseudoClasses(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets or sets a value indicating whether the button is inactive.
|
||||
|
/// </summary>
|
||||
|
internal bool IsInactive |
||||
|
{ |
||||
|
get { return _isInactive; } |
||||
|
set |
||||
|
{ |
||||
|
if (_isInactive != value) |
||||
|
{ |
||||
|
_isInactive = value; |
||||
|
SetPseudoClasses(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets or sets a value indicating whether the button is selected.
|
||||
|
/// </summary>
|
||||
|
internal bool IsSelected |
||||
|
{ |
||||
|
get { return _isSelected; } |
||||
|
set |
||||
|
{ |
||||
|
if (_isSelected != value) |
||||
|
{ |
||||
|
_isSelected = value; |
||||
|
SetPseudoClasses(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Builds the visual tree for the
|
||||
|
/// <see cref="T:System.Windows.Controls.Primitives.CalendarButton" />
|
||||
|
/// when a new template is applied.
|
||||
|
/// </summary>
|
||||
|
protected override void OnTemplateApplied(TemplateAppliedEventArgs e) |
||||
|
{ |
||||
|
base.OnTemplateApplied(e); |
||||
|
SetPseudoClasses(); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Sets PseudoClasses based on current state.
|
||||
|
/// </summary>
|
||||
|
private void SetPseudoClasses() |
||||
|
{ |
||||
|
PseudoClasses.Set(":selected", IsSelected); |
||||
|
PseudoClasses.Set(":inactive", IsInactive); |
||||
|
PseudoClasses.Set(":btnfocused", IsCalendarButtonFocused && IsEnabled); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Occurs when the left mouse button is pressed (or when the tip of the
|
||||
|
/// stylus touches the tablet PC) while the mouse pointer is over a
|
||||
|
/// UIElement.
|
||||
|
/// </summary>
|
||||
|
public event EventHandler<PointerPressedEventArgs> CalendarLeftMouseButtonDown; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Occurs when the left mouse button is released (or the tip of the
|
||||
|
/// stylus is removed from the tablet PC) while the mouse (or the
|
||||
|
/// stylus) is over a UIElement (or while a UIElement holds mouse
|
||||
|
/// capture).
|
||||
|
/// </summary>
|
||||
|
public event EventHandler<PointerReleasedEventArgs> CalendarLeftMouseButtonUp; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Provides class handling for the MouseLeftButtonDown event that
|
||||
|
/// occurs when the left mouse button is pressed while the mouse pointer
|
||||
|
/// is over this control.
|
||||
|
/// </summary>
|
||||
|
/// <param name="e">The event data. </param>
|
||||
|
/// <exception cref="System.ArgumentNullException">
|
||||
|
/// e is a null reference (Nothing in Visual Basic).
|
||||
|
/// </exception>
|
||||
|
/// <remarks>
|
||||
|
/// This method marks the MouseLeftButtonDown event as handled by
|
||||
|
/// setting the MouseButtonEventArgs.Handled property of the event data
|
||||
|
/// to true when the button is enabled and its ClickMode is not set to
|
||||
|
/// Hover. Since this method marks the MouseLeftButtonDown event as
|
||||
|
/// handled in some situations, you should use the Click event instead
|
||||
|
/// to detect a button click.
|
||||
|
/// </remarks>
|
||||
|
protected override void OnPointerPressed(PointerPressedEventArgs e) |
||||
|
{ |
||||
|
base.OnPointerPressed(e); |
||||
|
if (e.MouseButton == MouseButton.Left) |
||||
|
CalendarLeftMouseButtonDown?.Invoke(this, e); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Provides handling for the MouseLeftButtonUp event that occurs when
|
||||
|
/// the left mouse button is released while the mouse pointer is over
|
||||
|
/// this control.
|
||||
|
/// </summary>
|
||||
|
/// <param name="e">The event data.</param>
|
||||
|
/// <exception cref="System.ArgumentNullException">
|
||||
|
/// e is a null reference (Nothing in Visual Basic).
|
||||
|
/// </exception>
|
||||
|
/// <remarks>
|
||||
|
/// This method marks the MouseLeftButtonUp event as handled by setting
|
||||
|
/// the MouseButtonEventArgs.Handled property of the event data to true
|
||||
|
/// when the button is enabled and its ClickMode is not set to Hover.
|
||||
|
/// Since this method marks the MouseLeftButtonUp event as handled in
|
||||
|
/// some situations, you should use the Click event instead to detect a
|
||||
|
/// button click.
|
||||
|
/// </remarks>
|
||||
|
protected override void OnPointerReleased(PointerReleasedEventArgs e) |
||||
|
{ |
||||
|
base.OnPointerReleased(e); |
||||
|
if (e.MouseButton == MouseButton.Left) |
||||
|
CalendarLeftMouseButtonUp?.Invoke(this, e); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// We need to simulate the MouseLeftButtonUp event for the
|
||||
|
/// CalendarButton that stays in Pressed state after MouseCapture is
|
||||
|
/// released since there is no actual MouseLeftButtonUp event for the
|
||||
|
/// release.
|
||||
|
/// </summary>
|
||||
|
/// <param name="e">Event arguments.</param>
|
||||
|
internal void SendMouseLeftButtonUp(PointerReleasedEventArgs e) |
||||
|
{ |
||||
|
e.Handled = false; |
||||
|
base.OnPointerReleased(e); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,79 @@ |
|||||
|
// (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.
|
||||
|
|
||||
|
using System; |
||||
|
using System.Diagnostics; |
||||
|
|
||||
|
namespace Avalonia.Controls |
||||
|
{ |
||||
|
public sealed class CalendarDateRange |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Gets the first date in the represented range.
|
||||
|
/// </summary>
|
||||
|
/// <value>The first date in the represented range.</value>
|
||||
|
public DateTime Start { get; private set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets the last date in the represented range.
|
||||
|
/// </summary>
|
||||
|
/// <value>The last date in the represented range.</value>
|
||||
|
public DateTime End { get; private set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Initializes a new instance of the
|
||||
|
/// <see cref="T:System.Windows.Controls.CalendarDateRange" /> class
|
||||
|
/// with a single date.
|
||||
|
/// </summary>
|
||||
|
/// <param name="day">The date to be represented by the range.</param>
|
||||
|
public CalendarDateRange(DateTime day) |
||||
|
{ |
||||
|
Start = day; |
||||
|
End = day; |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Initializes a new instance of the
|
||||
|
/// <see cref="T:System.Windows.Controls.CalendarDateRange" /> class
|
||||
|
/// with a range of dates.
|
||||
|
/// </summary>
|
||||
|
/// <param name="start">
|
||||
|
/// The start of the range to be represented.
|
||||
|
/// </param>
|
||||
|
/// <param name="end">The end of the range to be represented.</param>
|
||||
|
public CalendarDateRange(DateTime start, DateTime end) |
||||
|
{ |
||||
|
if (DateTime.Compare(end, start) >= 0) |
||||
|
{ |
||||
|
Start = start; |
||||
|
End = end; |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
// Always use the start for ranges on the same day
|
||||
|
Start = start; |
||||
|
End = start; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Returns true if any day in the given DateTime range is contained in
|
||||
|
/// the current CalendarDateRange.
|
||||
|
/// </summary>
|
||||
|
/// <param name="range">Inherited code: Requires comment 1.</param>
|
||||
|
/// <returns>Inherited code: Requires comment 2.</returns>
|
||||
|
internal bool ContainsAny(CalendarDateRange range) |
||||
|
{ |
||||
|
Debug.Assert(range != null, "range should not be null!"); |
||||
|
|
||||
|
int start = DateTime.Compare(Start, range.Start); |
||||
|
|
||||
|
// Check if any part of the supplied range is contained by this
|
||||
|
// range or if the supplied range completely covers this range.
|
||||
|
return (start <= 0 && DateTime.Compare(End, range.Start) >= 0) || |
||||
|
(start >= 0 && DateTime.Compare(Start, range.End) <= 0); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,253 @@ |
|||||
|
// (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.
|
||||
|
|
||||
|
using Avalonia.Input; |
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Globalization; |
||||
|
using System.Text; |
||||
|
|
||||
|
namespace Avalonia.Controls.Primitives |
||||
|
{ |
||||
|
public sealed class CalendarDayButton : Button |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Default content for the CalendarDayButton.
|
||||
|
/// </summary>
|
||||
|
private const int DefaultContent = 1; |
||||
|
|
||||
|
private bool _isCurrent; |
||||
|
private bool _ignoringMouseOverState; |
||||
|
private bool _isBlackout; |
||||
|
private bool _isToday; |
||||
|
private bool _isInactive; |
||||
|
private bool _isSelected; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Initializes a new instance of the
|
||||
|
/// <see cref="T:Avalonia.Controls.Primitives.CalendarDayButton" />
|
||||
|
/// class.
|
||||
|
/// </summary>
|
||||
|
public CalendarDayButton() |
||||
|
: base() |
||||
|
{ |
||||
|
//Focusable = false;
|
||||
|
Content = DefaultContent.ToString(CultureInfo.CurrentCulture); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets or sets the Calendar associated with this button.
|
||||
|
/// </summary>
|
||||
|
internal Calendar Owner { get; set; } |
||||
|
internal int Index { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets or sets a value indicating whether the button is the focused
|
||||
|
/// element on the Calendar control.
|
||||
|
/// </summary>
|
||||
|
internal bool IsCurrent |
||||
|
{ |
||||
|
get { return _isCurrent; } |
||||
|
set |
||||
|
{ |
||||
|
if (_isCurrent != value) |
||||
|
{ |
||||
|
_isCurrent = value; |
||||
|
SetPseudoClasses(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Ensure the button is not in the MouseOver state.
|
||||
|
/// </summary>
|
||||
|
/// <remarks>
|
||||
|
/// If a button is in the MouseOver state when a Popup is closed (as is
|
||||
|
/// the case when you select a date in the DatePicker control), it will
|
||||
|
/// continue to think it's in the mouse over state even when the Popup
|
||||
|
/// opens again and it's not. This method is used to forcibly clear the
|
||||
|
/// state by changing the CommonStates state group.
|
||||
|
/// </remarks>
|
||||
|
internal void IgnoreMouseOverState() |
||||
|
{ |
||||
|
// TODO: Investigate whether this needs to be done by changing the
|
||||
|
// state everytime we change any state, or if it can be done once
|
||||
|
// to properly reset the control.
|
||||
|
|
||||
|
_ignoringMouseOverState = false; |
||||
|
|
||||
|
// If the button thinks it's in the MouseOver state (which can
|
||||
|
// happen when a Popup is closed before the button can change state)
|
||||
|
// we will override the state so it shows up as normal.
|
||||
|
if (IsPointerOver) |
||||
|
{ |
||||
|
_ignoringMouseOverState = true; |
||||
|
SetPseudoClasses(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets or sets a value indicating whether this is a blackout date.
|
||||
|
/// </summary>
|
||||
|
internal bool IsBlackout |
||||
|
{ |
||||
|
get { return _isBlackout; } |
||||
|
set |
||||
|
{ |
||||
|
if (_isBlackout != value) |
||||
|
{ |
||||
|
_isBlackout = value; |
||||
|
SetPseudoClasses(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets or sets a value indicating whether this button represents
|
||||
|
/// today.
|
||||
|
/// </summary>
|
||||
|
internal bool IsToday |
||||
|
{ |
||||
|
get { return _isToday; } |
||||
|
set |
||||
|
{ |
||||
|
if (_isToday != value) |
||||
|
{ |
||||
|
_isToday = value; |
||||
|
SetPseudoClasses(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
/// <summary>
|
||||
|
/// Gets or sets a value indicating whether the button is inactive.
|
||||
|
/// </summary>
|
||||
|
internal bool IsInactive |
||||
|
{ |
||||
|
get { return _isInactive; } |
||||
|
set |
||||
|
{ |
||||
|
if (_isInactive != value) |
||||
|
{ |
||||
|
_isInactive = value; |
||||
|
SetPseudoClasses(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets or sets a value indicating whether the button is selected.
|
||||
|
/// </summary>
|
||||
|
internal bool IsSelected |
||||
|
{ |
||||
|
get { return _isSelected; } |
||||
|
set |
||||
|
{ |
||||
|
if (_isSelected != value) |
||||
|
{ |
||||
|
_isSelected = value; |
||||
|
SetPseudoClasses(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
protected override void OnTemplateApplied(TemplateAppliedEventArgs e) |
||||
|
{ |
||||
|
base.OnTemplateApplied(e); |
||||
|
SetPseudoClasses(); |
||||
|
} |
||||
|
private void SetPseudoClasses() |
||||
|
{ |
||||
|
if (_ignoringMouseOverState) |
||||
|
{ |
||||
|
PseudoClasses.Set(":pressed", IsPressed); |
||||
|
PseudoClasses.Set(":disabled", !IsEnabled); |
||||
|
} |
||||
|
|
||||
|
PseudoClasses.Set(":selected", IsSelected); |
||||
|
PseudoClasses.Set(":inactive", IsInactive); |
||||
|
PseudoClasses.Set(":today", IsToday); |
||||
|
PseudoClasses.Set(":blackout", IsBlackout); |
||||
|
PseudoClasses.Set(":dayfocused", IsCurrent && IsEnabled); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Occurs when the left mouse button is pressed (or when the tip of the
|
||||
|
/// stylus touches the tablet PC) while the mouse pointer is over a
|
||||
|
/// UIElement.
|
||||
|
/// </summary>
|
||||
|
public event EventHandler<PointerPressedEventArgs> CalendarDayButtonMouseDown; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Occurs when the left mouse button is released (or the tip of the
|
||||
|
/// stylus is removed from the tablet PC) while the mouse (or the
|
||||
|
/// stylus) is over a UIElement (or while a UIElement holds mouse
|
||||
|
/// capture).
|
||||
|
/// </summary>
|
||||
|
public event EventHandler<PointerReleasedEventArgs> CalendarDayButtonMouseUp; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Provides class handling for the MouseLeftButtonDown event that
|
||||
|
/// occurs when the left mouse button is pressed while the mouse pointer
|
||||
|
/// is over this control.
|
||||
|
/// </summary>
|
||||
|
/// <param name="e">The event data. </param>
|
||||
|
/// <exception cref="System.ArgumentNullException">
|
||||
|
/// e is a null reference (Nothing in Visual Basic).
|
||||
|
/// </exception>
|
||||
|
/// <remarks>
|
||||
|
/// This method marks the MouseLeftButtonDown event as handled by
|
||||
|
/// setting the MouseButtonEventArgs.Handled property of the event data
|
||||
|
/// to true when the button is enabled and its ClickMode is not set to
|
||||
|
/// Hover. Since this method marks the MouseLeftButtonDown event as
|
||||
|
/// handled in some situations, you should use the Click event instead
|
||||
|
/// to detect a button click.
|
||||
|
/// </remarks>
|
||||
|
protected override void OnPointerPressed(PointerPressedEventArgs e) |
||||
|
{ |
||||
|
base.OnPointerPressed(e); |
||||
|
|
||||
|
if (e.MouseButton == MouseButton.Left) |
||||
|
CalendarDayButtonMouseDown?.Invoke(this, e); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Provides handling for the MouseLeftButtonUp event that occurs when
|
||||
|
/// the left mouse button is released while the mouse pointer is over
|
||||
|
/// this control.
|
||||
|
/// </summary>
|
||||
|
/// <param name="e">The event data.</param>
|
||||
|
/// <exception cref="System.ArgumentNullException">
|
||||
|
/// e is a null reference (Nothing in Visual Basic).
|
||||
|
/// </exception>
|
||||
|
/// <remarks>
|
||||
|
/// This method marks the MouseLeftButtonUp event as handled by setting
|
||||
|
/// the MouseButtonEventArgs.Handled property of the event data to true
|
||||
|
/// when the button is enabled and its ClickMode is not set to Hover.
|
||||
|
/// Since this method marks the MouseLeftButtonUp event as handled in
|
||||
|
/// some situations, you should use the Click event instead to detect a
|
||||
|
/// button click.
|
||||
|
/// </remarks>
|
||||
|
protected override void OnPointerReleased(PointerReleasedEventArgs e) |
||||
|
{ |
||||
|
base.OnPointerReleased(e); |
||||
|
|
||||
|
if (e.MouseButton == MouseButton.Left) |
||||
|
CalendarDayButtonMouseUp?.Invoke(this, e); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// We need to simulate the MouseLeftButtonUp event for the
|
||||
|
/// CalendarDayButton that stays in Pressed state after MouseCapture is
|
||||
|
/// released since there is no actual MouseLeftButtonUp event for the
|
||||
|
/// release.
|
||||
|
/// </summary>
|
||||
|
/// <param name="e">Event arguments.</param>
|
||||
|
internal void SendMouseLeftButtonUp(PointerReleasedEventArgs e) |
||||
|
{ |
||||
|
e.Handled = false; |
||||
|
base.OnPointerReleased(e); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,21 @@ |
|||||
|
// (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.
|
||||
|
|
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using Avalonia.Input; |
||||
|
using System.Diagnostics; |
||||
|
|
||||
|
namespace Avalonia.Controls.Primitives |
||||
|
{ |
||||
|
internal static class CalendarExtensions |
||||
|
{ |
||||
|
public static void GetMetaKeyState(InputModifiers modifiers, out bool ctrl, out bool shift) |
||||
|
{ |
||||
|
ctrl = (modifiers & InputModifiers.Control) == InputModifiers.Control; |
||||
|
shift = (modifiers & InputModifiers.Shift) == InputModifiers.Shift; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
File diff suppressed because it is too large
@ -0,0 +1,155 @@ |
|||||
|
// (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.
|
||||
|
|
||||
|
using System; |
||||
|
using System.Diagnostics; |
||||
|
using System.Globalization; |
||||
|
|
||||
|
namespace Avalonia.Controls |
||||
|
{ |
||||
|
internal static class DateTimeHelper |
||||
|
{ |
||||
|
public static DateTime? AddDays(DateTime time, int days) |
||||
|
{ |
||||
|
System.Globalization.Calendar cal = new GregorianCalendar(); |
||||
|
try |
||||
|
{ |
||||
|
return cal.AddDays(time, days); |
||||
|
} |
||||
|
catch (ArgumentException) |
||||
|
{ |
||||
|
return null; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public static DateTime? AddMonths(DateTime time, int months) |
||||
|
{ |
||||
|
System.Globalization.Calendar cal = new GregorianCalendar(); |
||||
|
try |
||||
|
{ |
||||
|
return cal.AddMonths(time, months); |
||||
|
} |
||||
|
catch (ArgumentException) |
||||
|
{ |
||||
|
return null; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public static DateTime? AddYears(DateTime time, int years) |
||||
|
{ |
||||
|
System.Globalization.Calendar cal = new GregorianCalendar(); |
||||
|
try |
||||
|
{ |
||||
|
return cal.AddYears(time, years); |
||||
|
} |
||||
|
catch (ArgumentException) |
||||
|
{ |
||||
|
return null; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public static int CompareDays(DateTime dt1, DateTime dt2) |
||||
|
{ |
||||
|
return DateTime.Compare(DiscardTime(dt1).Value, DiscardTime(dt2).Value); |
||||
|
} |
||||
|
|
||||
|
public static int CompareYearMonth(DateTime dt1, DateTime dt2) |
||||
|
{ |
||||
|
return (dt1.Year - dt2.Year) * 12 + (dt1.Month - dt2.Month); |
||||
|
} |
||||
|
|
||||
|
public static int DecadeOfDate(DateTime date) |
||||
|
{ |
||||
|
return date.Year - (date.Year % 10); |
||||
|
} |
||||
|
|
||||
|
public static DateTime DiscardDayTime(DateTime d) |
||||
|
{ |
||||
|
int year = d.Year; |
||||
|
int month = d.Month; |
||||
|
DateTime newD = new DateTime(year, month, 1, 0, 0, 0); |
||||
|
return newD; |
||||
|
} |
||||
|
|
||||
|
public static DateTime? DiscardTime(DateTime? d) |
||||
|
{ |
||||
|
if (d == null) |
||||
|
{ |
||||
|
return null; |
||||
|
} |
||||
|
return d.Value.Date; |
||||
|
} |
||||
|
|
||||
|
public static int EndOfDecade(DateTime date) |
||||
|
{ |
||||
|
return DecadeOfDate(date) + 9; |
||||
|
} |
||||
|
|
||||
|
public static DateTimeFormatInfo GetCurrentDateFormat() |
||||
|
{ |
||||
|
if (CultureInfo.CurrentCulture.Calendar is GregorianCalendar) |
||||
|
{ |
||||
|
return CultureInfo.CurrentCulture.DateTimeFormat; |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
foreach (System.Globalization.Calendar cal in CultureInfo.CurrentCulture.OptionalCalendars) |
||||
|
{ |
||||
|
if (cal is GregorianCalendar) |
||||
|
{ |
||||
|
// if the default calendar is not Gregorian, return the
|
||||
|
// first supported GregorianCalendar dtfi
|
||||
|
DateTimeFormatInfo dtfi = new CultureInfo(CultureInfo.CurrentCulture.Name).DateTimeFormat; |
||||
|
dtfi.Calendar = cal; |
||||
|
return dtfi; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// if there are no GregorianCalendars in the OptionalCalendars
|
||||
|
// list, use the invariant dtfi
|
||||
|
DateTimeFormatInfo dt = new CultureInfo(CultureInfo.InvariantCulture.Name).DateTimeFormat; |
||||
|
dt.Calendar = new GregorianCalendar(); |
||||
|
return dt; |
||||
|
} |
||||
|
} |
||||
|
public static bool InRange(DateTime date, CalendarDateRange range) |
||||
|
{ |
||||
|
Debug.Assert(DateTime.Compare(range.Start, range.End) < 1, "The range should start before it ends!"); |
||||
|
|
||||
|
if (CompareDays(date, range.Start) > -1 && CompareDays(date, range.End) < 1) |
||||
|
{ |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
public static string ToYearMonthPatternString(DateTime date) |
||||
|
{ |
||||
|
string result = string.Empty; |
||||
|
DateTimeFormatInfo format = GetCurrentDateFormat(); |
||||
|
|
||||
|
if (format != null) |
||||
|
{ |
||||
|
result = date.ToString(format.YearMonthPattern, format); |
||||
|
} |
||||
|
|
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
public static string ToYearString(DateTime date) |
||||
|
{ |
||||
|
string result = string.Empty; |
||||
|
DateTimeFormatInfo format = GetCurrentDateFormat(); |
||||
|
|
||||
|
if (format != null) |
||||
|
{ |
||||
|
result = date.Year.ToString(format); |
||||
|
} |
||||
|
|
||||
|
return result; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,361 @@ |
|||||
|
// (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.
|
||||
|
|
||||
|
using Avalonia.Threading; |
||||
|
using System; |
||||
|
using System.Collections.ObjectModel; |
||||
|
using System.Threading; |
||||
|
|
||||
|
namespace Avalonia.Controls.Primitives |
||||
|
{ |
||||
|
public sealed class SelectedDatesCollection : ObservableCollection<DateTime> |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Inherited code: Requires comment.
|
||||
|
/// </summary>
|
||||
|
private Collection<DateTime> _addedItems; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Inherited code: Requires comment.
|
||||
|
/// </summary>
|
||||
|
private bool _isCleared; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Inherited code: Requires comment.
|
||||
|
/// </summary>
|
||||
|
private bool _isRangeAdded; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Inherited code: Requires comment.
|
||||
|
/// </summary>
|
||||
|
private Calendar _owner; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Initializes a new instance of the
|
||||
|
/// <see cref="T:Avalonia.Controls.Primitives.SelectedDatesCollection" />
|
||||
|
/// class.
|
||||
|
/// </summary>
|
||||
|
/// <param name="owner">
|
||||
|
/// The <see cref="T:Avalonia.Controls.Calendar" /> associated
|
||||
|
/// with this object.
|
||||
|
/// </param>
|
||||
|
public SelectedDatesCollection(Calendar owner) |
||||
|
{ |
||||
|
_owner = owner; |
||||
|
_addedItems = new Collection<DateTime>(); |
||||
|
} |
||||
|
|
||||
|
private void InvokeCollectionChanged(System.Collections.IList removedItems, System.Collections.IList addedItems) |
||||
|
{ |
||||
|
_owner.OnSelectedDatesCollectionChanged(new SelectionChangedEventArgs(null, addedItems, removedItems)); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Adds all the dates in the specified range, which includes the first
|
||||
|
/// and last dates, to the collection.
|
||||
|
/// </summary>
|
||||
|
/// <param name="start">The first date to add to the collection.</param>
|
||||
|
/// <param name="end">The last date to add to the collection.</param>
|
||||
|
public void AddRange(DateTime start, DateTime end) |
||||
|
{ |
||||
|
DateTime? rangeStart; |
||||
|
|
||||
|
// increment parameter specifies if the Days were selected in
|
||||
|
// Descending order or Ascending order based on this value, we add
|
||||
|
// the days in the range either in Ascending order or in Descending
|
||||
|
// order
|
||||
|
int increment = (DateTime.Compare(end, start) >= 0) ? 1 : -1; |
||||
|
|
||||
|
_addedItems.Clear(); |
||||
|
|
||||
|
rangeStart = start; |
||||
|
_isRangeAdded = true; |
||||
|
|
||||
|
if (_owner.IsMouseSelection) |
||||
|
{ |
||||
|
// In Mouse Selection we allow the user to be able to add
|
||||
|
// multiple ranges in one action in MultipleRange Mode. In
|
||||
|
// SingleRange Mode, we only add the first selected range.
|
||||
|
while (rangeStart.HasValue && DateTime.Compare(end, rangeStart.Value) != -increment) |
||||
|
{ |
||||
|
if (Calendar.IsValidDateSelection(_owner, rangeStart)) |
||||
|
{ |
||||
|
Add(rangeStart.Value); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
if (_owner.SelectionMode == CalendarSelectionMode.SingleRange) |
||||
|
{ |
||||
|
_owner.HoverEnd = rangeStart.Value.AddDays(-increment); |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
rangeStart = DateTimeHelper.AddDays(rangeStart.Value, increment); |
||||
|
} |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
// If CalendarSelectionMode.SingleRange and a user
|
||||
|
// programmatically tries to add multiple ranges, we will throw
|
||||
|
// away the old range and replace it with the new one. In order
|
||||
|
// to provide the removed items without an additional event, we
|
||||
|
// are calling ClearInternal
|
||||
|
if (_owner.SelectionMode == CalendarSelectionMode.SingleRange && Count > 0) |
||||
|
{ |
||||
|
foreach (DateTime item in this) |
||||
|
{ |
||||
|
_owner.RemovedItems.Add(item); |
||||
|
} |
||||
|
ClearInternal(); |
||||
|
} |
||||
|
|
||||
|
while (rangeStart.HasValue && DateTime.Compare(end, rangeStart.Value) != -increment) |
||||
|
{ |
||||
|
Add(rangeStart.Value); |
||||
|
rangeStart = DateTimeHelper.AddDays(rangeStart.Value, increment); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
_owner.OnSelectedDatesCollectionChanged(new SelectionChangedEventArgs(null, _addedItems, _owner.RemovedItems)); |
||||
|
_owner.RemovedItems.Clear(); |
||||
|
_owner.UpdateMonths(); |
||||
|
_isRangeAdded = false; |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Removes all items from the collection.
|
||||
|
/// </summary>
|
||||
|
/// <remarks>
|
||||
|
/// This implementation raises the CollectionChanged event.
|
||||
|
/// </remarks>
|
||||
|
protected override void ClearItems() |
||||
|
{ |
||||
|
EnsureValidThread(); |
||||
|
|
||||
|
Collection<DateTime> addedItems = new Collection<DateTime>(); |
||||
|
Collection<DateTime> removedItems = new Collection<DateTime>(); |
||||
|
|
||||
|
foreach (DateTime item in this) |
||||
|
{ |
||||
|
removedItems.Add(item); |
||||
|
} |
||||
|
|
||||
|
base.ClearItems(); |
||||
|
|
||||
|
// The event fires after SelectedDate changes
|
||||
|
if (_owner.SelectionMode != CalendarSelectionMode.None && _owner.SelectedDate != null) |
||||
|
{ |
||||
|
_owner.SelectedDate = null; |
||||
|
} |
||||
|
|
||||
|
if (removedItems.Count != 0) |
||||
|
{ |
||||
|
InvokeCollectionChanged(removedItems, addedItems); |
||||
|
} |
||||
|
_owner.UpdateMonths(); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Inserts an item into the collection at the specified index.
|
||||
|
/// </summary>
|
||||
|
/// <param name="index">
|
||||
|
/// The zero-based index at which item should be inserted.
|
||||
|
/// </param>
|
||||
|
/// <param name="item">The object to insert.</param>
|
||||
|
/// <remarks>
|
||||
|
/// This implementation raises the CollectionChanged event.
|
||||
|
/// </remarks>
|
||||
|
protected override void InsertItem(int index, DateTime item) |
||||
|
{ |
||||
|
EnsureValidThread(); |
||||
|
|
||||
|
if (!Contains(item)) |
||||
|
{ |
||||
|
Collection<DateTime> addedItems = new Collection<DateTime>(); |
||||
|
|
||||
|
if (CheckSelectionMode()) |
||||
|
{ |
||||
|
if (Calendar.IsValidDateSelection(_owner, item)) |
||||
|
{ |
||||
|
// If the Collection is cleared since it is SingleRange
|
||||
|
// and it had another range set the index to 0
|
||||
|
if (_isCleared) |
||||
|
{ |
||||
|
index = 0; |
||||
|
_isCleared = false; |
||||
|
} |
||||
|
|
||||
|
base.InsertItem(index, item); |
||||
|
|
||||
|
// The event fires after SelectedDate changes
|
||||
|
if (index == 0 && !(_owner.SelectedDate.HasValue && DateTime.Compare(_owner.SelectedDate.Value, item) == 0)) |
||||
|
{ |
||||
|
_owner.SelectedDate = item; |
||||
|
} |
||||
|
|
||||
|
if (!_isRangeAdded) |
||||
|
{ |
||||
|
addedItems.Add(item); |
||||
|
|
||||
|
InvokeCollectionChanged(_owner.RemovedItems, addedItems); |
||||
|
_owner.RemovedItems.Clear(); |
||||
|
int monthDifference = DateTimeHelper.CompareYearMonth(item, _owner.DisplayDateInternal); |
||||
|
|
||||
|
if (monthDifference < 2 && monthDifference > -2) |
||||
|
{ |
||||
|
_owner.UpdateMonths(); |
||||
|
} |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
_addedItems.Add(item); |
||||
|
} |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
throw new ArgumentOutOfRangeException("SelectedDate value is not valid."); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Removes the item at the specified index of the collection.
|
||||
|
/// </summary>
|
||||
|
/// <param name="index">
|
||||
|
/// The zero-based index of the element to remove.
|
||||
|
/// </param>
|
||||
|
/// <remarks>
|
||||
|
/// This implementation raises the CollectionChanged event.
|
||||
|
/// </remarks>
|
||||
|
protected override void RemoveItem(int index) |
||||
|
{ |
||||
|
EnsureValidThread(); |
||||
|
|
||||
|
if (index >= Count) |
||||
|
{ |
||||
|
base.RemoveItem(index); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
Collection<DateTime> addedItems = new Collection<DateTime>(); |
||||
|
Collection<DateTime> removedItems = new Collection<DateTime>(); |
||||
|
int monthDifference = DateTimeHelper.CompareYearMonth(this[index], _owner.DisplayDateInternal); |
||||
|
|
||||
|
removedItems.Add(this[index]); |
||||
|
base.RemoveItem(index); |
||||
|
|
||||
|
// The event fires after SelectedDate changes
|
||||
|
if (index == 0) |
||||
|
{ |
||||
|
if (Count > 0) |
||||
|
{ |
||||
|
_owner.SelectedDate = this[0]; |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
_owner.SelectedDate = null; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
InvokeCollectionChanged(removedItems, addedItems); |
||||
|
|
||||
|
if (monthDifference < 2 && monthDifference > -2) |
||||
|
{ |
||||
|
_owner.UpdateMonths(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Replaces the element at the specified index.
|
||||
|
/// </summary>
|
||||
|
/// <param name="index">
|
||||
|
/// The zero-based index of the element to replace.
|
||||
|
/// </param>
|
||||
|
/// <param name="item">
|
||||
|
/// The new value for the element at the specified index.
|
||||
|
/// </param>
|
||||
|
/// <remarks>
|
||||
|
/// This implementation raises the CollectionChanged event.
|
||||
|
/// </remarks>
|
||||
|
protected override void SetItem(int index, DateTime item) |
||||
|
{ |
||||
|
EnsureValidThread(); |
||||
|
|
||||
|
if (!Contains(item)) |
||||
|
{ |
||||
|
Collection<DateTime> addedItems = new Collection<DateTime>(); |
||||
|
Collection<DateTime> removedItems = new Collection<DateTime>(); |
||||
|
|
||||
|
if (index >= Count) |
||||
|
{ |
||||
|
base.SetItem(index, item); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
if (item != null && DateTime.Compare(this[index], item) != 0 && Calendar.IsValidDateSelection(_owner, item)) |
||||
|
{ |
||||
|
removedItems.Add(this[index]); |
||||
|
base.SetItem(index, item); |
||||
|
addedItems.Add(item); |
||||
|
|
||||
|
// The event fires after SelectedDate changes
|
||||
|
if (index == 0 && !(_owner.SelectedDate.HasValue && DateTime.Compare(_owner.SelectedDate.Value, item) == 0)) |
||||
|
{ |
||||
|
_owner.SelectedDate = item; |
||||
|
} |
||||
|
InvokeCollectionChanged(removedItems, addedItems); |
||||
|
|
||||
|
int monthDifference = DateTimeHelper.CompareYearMonth(item, _owner.DisplayDateInternal); |
||||
|
|
||||
|
if (monthDifference < 2 && monthDifference > -2) |
||||
|
{ |
||||
|
_owner.UpdateMonths(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
internal void ClearInternal() |
||||
|
{ |
||||
|
base.ClearItems(); |
||||
|
} |
||||
|
|
||||
|
private bool CheckSelectionMode() |
||||
|
{ |
||||
|
if (_owner.SelectionMode == CalendarSelectionMode.None) |
||||
|
{ |
||||
|
throw new InvalidOperationException("The SelectedDate property cannot be set when the selection mode is None."); |
||||
|
} |
||||
|
if (_owner.SelectionMode == CalendarSelectionMode.SingleDate && Count > 0) |
||||
|
{ |
||||
|
throw new InvalidOperationException("The SelectedDates collection can be changed only in a multiple selection mode. Use the SelectedDate in a single selection mode."); |
||||
|
} |
||||
|
|
||||
|
// if user tries to add an item into the SelectedDates in
|
||||
|
// SingleRange mode, we throw away the old range and replace it with
|
||||
|
// the new one in order to provide the removed items without an
|
||||
|
// additional event, we are calling ClearInternal
|
||||
|
if (_owner.SelectionMode == CalendarSelectionMode.SingleRange && !_isRangeAdded && Count > 0) |
||||
|
{ |
||||
|
foreach (DateTime item in this) |
||||
|
{ |
||||
|
_owner.RemovedItems.Add(item); |
||||
|
} |
||||
|
ClearInternal(); |
||||
|
_isCleared = true; |
||||
|
} |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
private void EnsureValidThread() |
||||
|
{ |
||||
|
Dispatcher.UIThread.VerifyAccess(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -1,53 +0,0 @@ |
|||||
// 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 Avalonia.Layout; |
|
||||
using Splat; |
|
||||
|
|
||||
namespace Avalonia.Diagnostics |
|
||||
{ |
|
||||
public class LogManager : ILogManager |
|
||||
{ |
|
||||
private static LogManager s_instance; |
|
||||
|
|
||||
public static LogManager Instance => s_instance ?? (s_instance = new LogManager()); |
|
||||
|
|
||||
public ILogger Logger |
|
||||
{ |
|
||||
get; |
|
||||
set; |
|
||||
} |
|
||||
|
|
||||
public bool LogPropertyMessages |
|
||||
{ |
|
||||
get; |
|
||||
set; |
|
||||
} |
|
||||
|
|
||||
public bool LogLayoutMessages |
|
||||
{ |
|
||||
get; |
|
||||
set; |
|
||||
} |
|
||||
|
|
||||
public static void Enable(ILogger logger) |
|
||||
{ |
|
||||
Instance.Logger = logger; |
|
||||
Locator.CurrentMutable.Register(() => Instance, typeof(ILogManager)); |
|
||||
} |
|
||||
|
|
||||
public IFullLogger GetLogger(Type type) |
|
||||
{ |
|
||||
if ((type == typeof(AvaloniaObject) && LogPropertyMessages) || |
|
||||
(type == typeof(Layoutable) && LogLayoutMessages)) |
|
||||
{ |
|
||||
return new WrappingFullLogger(Logger, type); |
|
||||
} |
|
||||
else |
|
||||
{ |
|
||||
return new WrappingFullLogger(new NullLogger(), type); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -0,0 +1,51 @@ |
|||||
|
using System; |
||||
|
using Avalonia.Controls; |
||||
|
using Serilog; |
||||
|
using SerilogLevel = Serilog.Events.LogEventLevel; |
||||
|
|
||||
|
namespace Avalonia.Logging.Serilog |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Extension methods for Serilog logging.
|
||||
|
/// </summary>
|
||||
|
public static class SerilogExtensions |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Logs Avalonia events to the <see cref="System.Diagnostics.Debug"/> sink.
|
||||
|
/// </summary>
|
||||
|
/// <typeparam name="T">The application class type.</typeparam>
|
||||
|
/// <param name="builder">The app builder instance.</param>
|
||||
|
/// <param name="level">The minimum level to log.</param>
|
||||
|
/// <returns>The app builder instance.</returns>
|
||||
|
public static T LogToDebug<T>( |
||||
|
this T builder, |
||||
|
LogEventLevel level = LogEventLevel.Warning) |
||||
|
where T : AppBuilderBase<T>, new() |
||||
|
{ |
||||
|
SerilogLogger.Initialize(new LoggerConfiguration() |
||||
|
.MinimumLevel.Is((SerilogLevel)level) |
||||
|
.WriteTo.Debug(outputTemplate: "{Area}: {Message}") |
||||
|
.CreateLogger()); |
||||
|
return builder; |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Logs Avalonia events to the <see cref="System.Diagnostics.Trace"/> sink.
|
||||
|
/// </summary>
|
||||
|
/// <typeparam name="T">The application class type.</typeparam>
|
||||
|
/// <param name="builder">The app builder instance.</param>
|
||||
|
/// <param name="level">The minimum level to log.</param>
|
||||
|
/// <returns>The app builder instance.</returns>
|
||||
|
public static T LogToTrace<T>( |
||||
|
this T builder, |
||||
|
LogEventLevel level = LogEventLevel.Warning) |
||||
|
where T : AppBuilderBase<T>, new() |
||||
|
{ |
||||
|
SerilogLogger.Initialize(new LoggerConfiguration() |
||||
|
.MinimumLevel.Is((SerilogLevel)level) |
||||
|
.WriteTo.Trace(outputTemplate: "{Area}: {Message}") |
||||
|
.CreateLogger()); |
||||
|
return builder; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,30 @@ |
|||||
|
<!-- |
||||
|
// (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"> |
||||
|
<Style Selector="Calendar"> |
||||
|
<!--<Setter Property="Focusable" Value="False" />--> |
||||
|
<Setter Property="BorderThickness" Value="{DynamicResource ThemeBorderThickness}" /> |
||||
|
<Setter Property="BorderBrush" Value="{DynamicResource ThemeBorderDarkBrush}" /> |
||||
|
<Setter Property="Background" Value="{DynamicResource ThemeBackgroundBrush}" /> |
||||
|
<Setter Property="HeaderBackground" Value="{DynamicResource ThemeAccentBrush2}" /> |
||||
|
<Setter Property="Template"> |
||||
|
<ControlTemplate> |
||||
|
<StackPanel Name="Root" |
||||
|
HorizontalAlignment="Center"> |
||||
|
|
||||
|
<CalendarItem Name="CalendarItem" |
||||
|
Background="{TemplateBinding Background}" |
||||
|
BorderBrush="{TemplateBinding BorderBrush}" |
||||
|
BorderThickness="{TemplateBinding BorderThickness}" |
||||
|
HeaderBackground="{TemplateBinding HeaderBackground}"/> |
||||
|
|
||||
|
</StackPanel> |
||||
|
</ControlTemplate> |
||||
|
</Setter> |
||||
|
</Style> |
||||
|
</Styles> |
||||
@ -0,0 +1,80 @@ |
|||||
|
<!-- |
||||
|
// (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"> |
||||
|
<Style Selector="CalendarButton"> |
||||
|
<Setter Property="Background" Value="{DynamicResource ThemeAccentBrush2}" /> |
||||
|
<Setter Property="FontSize" Value="{DynamicResource FontSizeSmall}" /> |
||||
|
<Setter Property="HorizontalContentAlignment" Value="Center" /> |
||||
|
<Setter Property="VerticalContentAlignment" Value="Center" /> |
||||
|
<Setter Property="MinWidth" Value="37" /> |
||||
|
<Setter Property="MinHeight" Value="38" /> |
||||
|
<Setter Property="Focusable" Value="False"/> |
||||
|
<Setter Property="Template"> |
||||
|
<ControlTemplate> |
||||
|
<Grid> |
||||
|
|
||||
|
<Rectangle Name="SelectedBackground" |
||||
|
Opacity="0.75" |
||||
|
Fill="{TemplateBinding Background}"/> |
||||
|
|
||||
|
<Rectangle Name="Background" |
||||
|
Opacity="0.5" |
||||
|
Fill="{TemplateBinding Background}"/> |
||||
|
|
||||
|
<!--Focusable="False"--> |
||||
|
<ContentControl Name="Content" |
||||
|
Foreground="#FF333333" |
||||
|
Content="{TemplateBinding Content}" |
||||
|
ContentTemplate="{TemplateBinding ContentTemplate}" |
||||
|
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" |
||||
|
VerticalAlignment="{TemplateBinding VerticalContentAlignment}" |
||||
|
FontSize="{TemplateBinding FontSize}" |
||||
|
Margin="1,0,1,1"/> |
||||
|
|
||||
|
<Rectangle Name="FocusVisual" |
||||
|
StrokeThickness="1" |
||||
|
Stroke="{DynamicResource HighlightBrush}" |
||||
|
IsHitTestVisible="False"/> |
||||
|
|
||||
|
</Grid> |
||||
|
</ControlTemplate> |
||||
|
</Setter> |
||||
|
</Style> |
||||
|
|
||||
|
<Style Selector="CalendarButton /template/ Rectangle#Background"> |
||||
|
<Setter Property="IsVisible" Value="False"/> |
||||
|
</Style> |
||||
|
<Style Selector="CalendarButton:pointerover /template/ Rectangle#Background"> |
||||
|
<Setter Property="IsVisible" Value="True"/> |
||||
|
</Style> |
||||
|
<Style Selector="CalendarButton:pressed /template/ Rectangle#Background"> |
||||
|
<Setter Property="IsVisible" Value="True"/> |
||||
|
</Style> |
||||
|
|
||||
|
<Style Selector="CalendarButton /template/ Rectangle#SelectedBackground"> |
||||
|
<Setter Property="IsVisible" Value="False"/> |
||||
|
</Style> |
||||
|
<Style Selector="CalendarButton:selected /template/ Rectangle#SelectedBackground"> |
||||
|
<Setter Property="IsVisible" Value="True"/> |
||||
|
</Style> |
||||
|
|
||||
|
<Style Selector="CalendarButton /template/ ContentControl#Content"> |
||||
|
<Setter Property="Foreground" Value="{DynamicResource ThemeForegroundBrush}"/> |
||||
|
</Style> |
||||
|
<Style Selector="CalendarButton:inactive /template/ ContentControl#Content"> |
||||
|
<Setter Property="Foreground" Value="{DynamicResource ThemeForegroundLightBrush}"/> |
||||
|
</Style> |
||||
|
|
||||
|
|
||||
|
<Style Selector="CalendarButton /template/ Rectangle#FocusVisual"> |
||||
|
<Setter Property="IsVisible" Value="False"/> |
||||
|
</Style> |
||||
|
<Style Selector="CalendarButton:btnfocused /template/ Rectangle#FocusVisual"> |
||||
|
<Setter Property="IsVisible" Value="True"/> |
||||
|
</Style> |
||||
|
</Styles> |
||||
@ -0,0 +1,116 @@ |
|||||
|
<!-- |
||||
|
// (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"> |
||||
|
<Style Selector="CalendarDayButton"> |
||||
|
<Setter Property="Background" Value="{DynamicResource ThemeAccentBrush2}" /> |
||||
|
<Setter Property="FontSize" Value="{DynamicResource FontSizeSmall}" /> |
||||
|
<Setter Property="HorizontalContentAlignment" Value="Center" /> |
||||
|
<Setter Property="VerticalContentAlignment" Value="Center" /> |
||||
|
<Setter Property="MinWidth" Value="5" /> |
||||
|
<Setter Property="MinHeight" Value="5" /> |
||||
|
<Setter Property="Focusable" Value="False"/> |
||||
|
<Setter Property="Template"> |
||||
|
<ControlTemplate> |
||||
|
<Panel Background="Transparent"> |
||||
|
|
||||
|
<Rectangle Name="TodayBackground" |
||||
|
Fill="{DynamicResource HighlightBrush}"/> |
||||
|
|
||||
|
<Rectangle Name="SelectedBackground" |
||||
|
Opacity="0.75" |
||||
|
Fill="{TemplateBinding Background}"/> |
||||
|
|
||||
|
<Rectangle Name="Background" |
||||
|
Opacity="0.5" |
||||
|
Fill="{TemplateBinding Background}"/> |
||||
|
|
||||
|
<ContentControl Name="Content" |
||||
|
Content="{TemplateBinding Content}" |
||||
|
ContentTemplate="{TemplateBinding ContentTemplate}" |
||||
|
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" |
||||
|
VerticalAlignment="{TemplateBinding VerticalContentAlignment}" |
||||
|
FontSize="{TemplateBinding FontSize}" |
||||
|
Margin="5,1,5,1"/> |
||||
|
|
||||
|
<Path Name="BlackoutVisual" |
||||
|
Margin="3" |
||||
|
HorizontalAlignment="Stretch" |
||||
|
VerticalAlignment="Stretch" |
||||
|
RenderTransformOrigin="0.5,0.5" |
||||
|
Fill="#FF000000" |
||||
|
Stretch="Fill" |
||||
|
Data="M8.1772461,11.029181 L10.433105,11.029181 L11.700684,12.801641 L12.973633,11.029181 L15.191895,11.029181 L12.844727,13.999395 L15.21875,17.060919 L12.962891,17.060919 L11.673828,15.256231 L10.352539,17.060919 L8.1396484,17.060919 L10.519043,14.042364 z" /> |
||||
|
|
||||
|
<Rectangle Name="FocusVisual" |
||||
|
StrokeThickness="1" |
||||
|
Stroke="{DynamicResource HighlightBrush}" |
||||
|
IsHitTestVisible="False"/> |
||||
|
|
||||
|
</Panel> |
||||
|
</ControlTemplate> |
||||
|
</Setter> |
||||
|
</Style> |
||||
|
|
||||
|
<Style Selector="CalendarDayButton /template/ Rectangle#Background"> |
||||
|
<Setter Property="IsVisible" Value="False"/> |
||||
|
</Style> |
||||
|
<Style Selector="CalendarDayButton:pointerover /template/ Rectangle#Background"> |
||||
|
<Setter Property="IsVisible" Value="True"/> |
||||
|
</Style> |
||||
|
<Style Selector="CalendarDayButton:pressed /template/ Rectangle#Background"> |
||||
|
<Setter Property="IsVisible" Value="True"/> |
||||
|
</Style> |
||||
|
|
||||
|
<Style Selector="CalendarDayButton /template/ Rectangle#SelectedBackground"> |
||||
|
<Setter Property="IsVisible" Value="False"/> |
||||
|
</Style> |
||||
|
<Style Selector="CalendarDayButton:selected /template/ Rectangle#SelectedBackground"> |
||||
|
<Setter Property="IsVisible" Value="True"/> |
||||
|
</Style> |
||||
|
|
||||
|
<Style Selector="CalendarDayButton /template/ ContentControl#Content"> |
||||
|
<Setter Property="Opacity" Value="1"/> |
||||
|
<Setter Property="Foreground" Value="{DynamicResource ThemeForegroundBrush}"/> |
||||
|
</Style> |
||||
|
<Style Selector="CalendarDayButton:disabled /template/ Rectangle#Background"> |
||||
|
<Setter Property="IsVisible" Value="False"/> |
||||
|
</Style> |
||||
|
<Style Selector="CalendarDayButton:disabled /template/ ContentControl#Content"> |
||||
|
<Setter Property="Opacity" Value="0.3"/> |
||||
|
</Style> |
||||
|
|
||||
|
<Style Selector="CalendarDayButton /template/ Rectangle#FocusVisual"> |
||||
|
<Setter Property="IsVisible" Value="False"/> |
||||
|
</Style> |
||||
|
<Style Selector="CalendarDayButton:dayfocused /template/ Rectangle#FocusVisual"> |
||||
|
<Setter Property="IsVisible" Value="True"/> |
||||
|
</Style> |
||||
|
|
||||
|
<Style Selector="CalendarDayButton /template/ Rectangle#TodayBackground"> |
||||
|
<Setter Property="IsVisible" Value="False"/> |
||||
|
</Style> |
||||
|
<Style Selector="CalendarDayButton:today /template/ Rectangle#TodayBackground"> |
||||
|
<Setter Property="IsVisible" Value="True"/> |
||||
|
</Style> |
||||
|
|
||||
|
|
||||
|
<Style Selector="CalendarDayButton:inactive /template/ ContentControl#Content"> |
||||
|
<Setter Property="Foreground" Value="{DynamicResource ThemeForegroundLightBrush}"/> |
||||
|
</Style> |
||||
|
<Style Selector="CalendarDayButton:today /template/ ContentControl#Content"> |
||||
|
<Setter Property="Foreground" Value="#FFFFFFFF"/> |
||||
|
</Style> |
||||
|
|
||||
|
<Style Selector="CalendarDayButton /template/ Path#BlackoutVisual"> |
||||
|
<Setter Property="Opacity" Value="0"/> |
||||
|
</Style> |
||||
|
<Style Selector="CalendarDayButton:blackout /template/ Path#BlackoutVisual"> |
||||
|
<Setter Property="Opacity" Value="0.3"/> |
||||
|
</Style> |
||||
|
|
||||
|
</Styles> |
||||
@ -0,0 +1,183 @@ |
|||||
|
<!-- |
||||
|
// (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="CalendarItem"> |
||||
|
<Setter Property="Template"> |
||||
|
<ControlTemplate> |
||||
|
<Panel> |
||||
|
<Border BorderThickness="{TemplateBinding BorderThickness}" |
||||
|
BorderBrush="{TemplateBinding BorderBrush}" |
||||
|
Background="{TemplateBinding Background}" |
||||
|
Margin="0,2,0,2" |
||||
|
CornerRadius="1"> |
||||
|
|
||||
|
<Border CornerRadius="1" |
||||
|
BorderBrush="{DynamicResource ThemeBackgroundBrush}" |
||||
|
BorderThickness="2"> |
||||
|
<Grid> |
||||
|
<Grid.RowDefinitions> |
||||
|
<RowDefinition Height="Auto" /> |
||||
|
<RowDefinition Height="*" /> |
||||
|
</Grid.RowDefinitions> |
||||
|
<Grid.ColumnDefinitions> |
||||
|
<ColumnDefinition Width="Auto" /> |
||||
|
<ColumnDefinition Width="Auto" /> |
||||
|
<ColumnDefinition Width="Auto" /> |
||||
|
</Grid.ColumnDefinitions> |
||||
|
|
||||
|
<Grid.Styles> |
||||
|
<Style Selector="Button.CalendarHeader"> |
||||
|
<Setter Property="Cursor" Value="Hand"/> |
||||
|
<Setter Property="Background" Value="Transparent"/> |
||||
|
<Setter Property="BorderThickness" Value="0"/> |
||||
|
</Style> |
||||
|
<Style Selector="Button.CalendarHeader:pressed /template/ ContentPresenter"> |
||||
|
<Setter Property="Background" Value="Transparent"/> |
||||
|
</Style> |
||||
|
|
||||
|
<Style Selector="Button.CalendarNavigation"> |
||||
|
<Setter Property="Height" Value="20"/> |
||||
|
<Setter Property="Width" Value="28"/> |
||||
|
</Style> |
||||
|
<Style Selector="Button.CalendarNavigation > Path"> |
||||
|
<Setter Property="Fill" Value="{DynamicResource ThemeForegroundBrush}"/> |
||||
|
</Style> |
||||
|
<Style Selector="Button.CalendarNavigation:pointerover > Path"> |
||||
|
<Setter Property="Fill" Value="{DynamicResource HighlightBrush}"/> |
||||
|
</Style> |
||||
|
|
||||
|
<Style Selector="Button#HeaderButton:pointerover"> |
||||
|
<Setter Property="Foreground" Value="{DynamicResource HighlightBrush}"/> |
||||
|
</Style> |
||||
|
</Grid.Styles> |
||||
|
|
||||
|
<Rectangle Grid.ColumnSpan="3" |
||||
|
Fill="{TemplateBinding HeaderBackground}" |
||||
|
Stretch="Fill" |
||||
|
VerticalAlignment="Top" |
||||
|
Height="22"/> |
||||
|
|
||||
|
<Button Name="PreviousButton" |
||||
|
Classes="CalendarHeader CalendarNavigation" |
||||
|
IsVisible="False" |
||||
|
HorizontalAlignment="Left"> |
||||
|
|
||||
|
<Path Margin="14,-6,0,0" |
||||
|
Height="10" |
||||
|
Width="6" |
||||
|
VerticalAlignment="Center" |
||||
|
HorizontalAlignment="Left" |
||||
|
Stretch="Fill" |
||||
|
Data="M288.75,232.25 L288.75,240.625 L283,236.625 z" /> |
||||
|
|
||||
|
</Button> |
||||
|
|
||||
|
<Button Name="HeaderButton" |
||||
|
Classes="CalendarHeader" |
||||
|
Grid.Column="1" |
||||
|
FontWeight="Bold" |
||||
|
FontSize="10.5" |
||||
|
HorizontalAlignment="Center" |
||||
|
VerticalAlignment="Center" |
||||
|
Padding="1,5,1,9"/> |
||||
|
|
||||
|
<Button Name="NextButton" |
||||
|
Classes="CalendarHeader CalendarNavigation" |
||||
|
Grid.Column="2" |
||||
|
IsVisible="False" |
||||
|
HorizontalAlignment="Right" > |
||||
|
|
||||
|
<Path Margin="0,-6,14,0" |
||||
|
Height="10" |
||||
|
Width="6" |
||||
|
Stretch="Fill" |
||||
|
VerticalAlignment="Center" |
||||
|
HorizontalAlignment="Right" |
||||
|
Data="M282.875,231.875 L282.875,240.375 L288.625,236 z" /> |
||||
|
|
||||
|
</Button> |
||||
|
|
||||
|
<Grid Name="MonthView" |
||||
|
Grid.Row="1" |
||||
|
Grid.ColumnSpan="3" |
||||
|
IsVisible="False" |
||||
|
Margin="6,-1,6,6"> |
||||
|
<Grid.RowDefinitions> |
||||
|
<RowDefinition Height="Auto" /> |
||||
|
<RowDefinition Height="Auto" /> |
||||
|
<RowDefinition Height="Auto" /> |
||||
|
<RowDefinition Height="Auto" /> |
||||
|
<RowDefinition Height="Auto" /> |
||||
|
<RowDefinition Height="Auto" /> |
||||
|
<RowDefinition Height="Auto" /> |
||||
|
</Grid.RowDefinitions> |
||||
|
<Grid.ColumnDefinitions> |
||||
|
<ColumnDefinition Width="Auto" /> |
||||
|
<ColumnDefinition Width="Auto" /> |
||||
|
<ColumnDefinition Width="Auto" /> |
||||
|
<ColumnDefinition Width="Auto" /> |
||||
|
<ColumnDefinition Width="Auto" /> |
||||
|
<ColumnDefinition Width="Auto" /> |
||||
|
<ColumnDefinition Width="Auto" /> |
||||
|
</Grid.ColumnDefinitions> |
||||
|
</Grid> |
||||
|
|
||||
|
<Grid Name="YearView" |
||||
|
Grid.Row="1" |
||||
|
Grid.ColumnSpan="3" |
||||
|
IsVisible="False" |
||||
|
Margin="6,-3,7,6"> |
||||
|
<Grid.RowDefinitions> |
||||
|
<RowDefinition Height="Auto" /> |
||||
|
<RowDefinition Height="Auto" /> |
||||
|
<RowDefinition Height="Auto" /> |
||||
|
</Grid.RowDefinitions> |
||||
|
<Grid.ColumnDefinitions> |
||||
|
<ColumnDefinition Width="Auto" /> |
||||
|
<ColumnDefinition Width="Auto" /> |
||||
|
<ColumnDefinition Width="Auto" /> |
||||
|
<ColumnDefinition Width="Auto" /> |
||||
|
</Grid.ColumnDefinitions> |
||||
|
</Grid> |
||||
|
|
||||
|
</Grid> |
||||
|
</Border> |
||||
|
</Border> |
||||
|
|
||||
|
|
||||
|
<Rectangle Name="DisabledVisual" |
||||
|
Stretch="Fill" |
||||
|
Fill="#FFFFFFFF" |
||||
|
Opacity="{DynamicResource ThemeDisabledOpacity}" |
||||
|
Margin="0,2,0,2" /> |
||||
|
|
||||
|
</Panel> |
||||
|
</ControlTemplate> |
||||
|
</Setter> |
||||
|
<Setter Property="DayTitleTemplate"> |
||||
|
<Template> |
||||
|
<TextBlock FontWeight="Bold" |
||||
|
FontSize="9.5" |
||||
|
Margin="0,4,0,4" |
||||
|
HorizontalAlignment="Center" |
||||
|
VerticalAlignment="Center" |
||||
|
Text="{Binding}" /> |
||||
|
</Template> |
||||
|
|
||||
|
</Setter> |
||||
|
</Style> |
||||
|
|
||||
|
<Style Selector="CalendarItem /template/ Rectangle#DisabledVisual"> |
||||
|
<Setter Property="IsVisible" Value="False"/> |
||||
|
</Style> |
||||
|
<Style Selector="CalendarItem:calendardisabled /template/ Rectangle#DisabledVisual"> |
||||
|
<Setter Property="IsVisible" Value="True"/> |
||||
|
</Style> |
||||
|
|
||||
|
</Styles> |
||||
@ -1,69 +0,0 @@ |
|||||
// 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.Reactive.Disposables; |
|
||||
using System.Reactive.Linq; |
|
||||
using System.Reactive.Subjects; |
|
||||
using Avalonia.Controls; |
|
||||
using Avalonia.Data; |
|
||||
using Avalonia.Styling; |
|
||||
|
|
||||
namespace Avalonia.Markup.Xaml.Data |
|
||||
{ |
|
||||
public class StyleResourceBinding : IBinding |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Initializes a new instance of the <see cref="StyleResourceBinding"/> class.
|
|
||||
/// </summary>
|
|
||||
/// <param name="name">The resource name.</param>
|
|
||||
public StyleResourceBinding(string name) |
|
||||
{ |
|
||||
Name = name; |
|
||||
} |
|
||||
|
|
||||
/// <inheritdoc/>
|
|
||||
public BindingMode Mode => BindingMode.OneTime; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets the resource name.
|
|
||||
/// </summary>
|
|
||||
public string Name { get; } |
|
||||
|
|
||||
/// <inheritdoc/>
|
|
||||
public BindingPriority Priority => BindingPriority.LocalValue; |
|
||||
|
|
||||
/// <inheritdoc/>
|
|
||||
public InstancedBinding Initiate( |
|
||||
IAvaloniaObject target, |
|
||||
AvaloniaProperty targetProperty, |
|
||||
object anchor = null, |
|
||||
bool enableDataValidation = false) |
|
||||
{ |
|
||||
var host = (target as IControl) ?? (anchor as IControl); |
|
||||
var style = anchor as IStyle; |
|
||||
var resource = AvaloniaProperty.UnsetValue; |
|
||||
|
|
||||
if (host != null) |
|
||||
{ |
|
||||
resource = host.FindResource(Name); |
|
||||
} |
|
||||
else if (style != null) |
|
||||
{ |
|
||||
if (!style.TryGetResource(Name, out resource)) |
|
||||
{ |
|
||||
resource = AvaloniaProperty.UnsetValue; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
if (resource != AvaloniaProperty.UnsetValue) |
|
||||
{ |
|
||||
return new InstancedBinding(resource, Priority); |
|
||||
} |
|
||||
else |
|
||||
{ |
|
||||
return null; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,25 +0,0 @@ |
|||||
// 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; |
|
||||
|
|
||||
namespace Avalonia.Markup.Xaml.MarkupExtensions |
|
||||
{ |
|
||||
public class StaticExtension : Portable.Xaml.Markup.StaticExtension |
|
||||
{ |
|
||||
public StaticExtension() |
|
||||
{ |
|
||||
} |
|
||||
|
|
||||
public StaticExtension(string member) |
|
||||
: base(member) |
|
||||
{ |
|
||||
} |
|
||||
|
|
||||
public override object ProvideValue(IServiceProvider serviceProvider) |
|
||||
{ |
|
||||
return base.ProvideValue(serviceProvider); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
} |
|
||||
@ -1,31 +0,0 @@ |
|||||
// 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 Avalonia.Data; |
|
||||
using Avalonia.Markup.Xaml.Data; |
|
||||
using System; |
|
||||
|
|
||||
namespace Avalonia.Markup.Xaml.MarkupExtensions |
|
||||
{ |
|
||||
using Portable.Xaml.Markup; |
|
||||
using PortableXaml; |
|
||||
|
|
||||
[MarkupExtensionReturnType(typeof(IBinding))] |
|
||||
public class StyleResourceExtension : MarkupExtension |
|
||||
{ |
|
||||
public StyleResourceExtension(string name) |
|
||||
{ |
|
||||
Name = name; |
|
||||
} |
|
||||
|
|
||||
public override object ProvideValue(IServiceProvider serviceProvider) |
|
||||
{ |
|
||||
return XamlBinding.FromMarkupExtensionContext( |
|
||||
new StyleResourceBinding(Name), |
|
||||
serviceProvider); |
|
||||
} |
|
||||
|
|
||||
[ConstructorArgument("name")] |
|
||||
public string Name { get; set; } |
|
||||
} |
|
||||
} |
|
||||
@ -1,23 +0,0 @@ |
|||||
// 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; |
|
||||
|
|
||||
namespace Avalonia.Markup.Xaml.MarkupExtensions |
|
||||
{ |
|
||||
public class TypeExtension : Portable.Xaml.Markup.TypeExtension |
|
||||
{ |
|
||||
public TypeExtension() |
|
||||
{ |
|
||||
} |
|
||||
|
|
||||
public TypeExtension(string typeName) : base(typeName) |
|
||||
{ |
|
||||
} |
|
||||
|
|
||||
public override object ProvideValue(IServiceProvider serviceProvider) |
|
||||
{ |
|
||||
return base.ProvideValue(serviceProvider); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,63 +0,0 @@ |
|||||
using Avalonia.Controls; |
|
||||
using Avalonia.Data; |
|
||||
using Avalonia.Styling; |
|
||||
using Portable.Xaml; |
|
||||
using Portable.Xaml.ComponentModel; |
|
||||
using System.ComponentModel; |
|
||||
using Portable.Xaml.Markup; |
|
||||
using System; |
|
||||
|
|
||||
namespace Avalonia.Markup.Xaml.PortableXaml |
|
||||
{ |
|
||||
internal class XamlBinding : IBinding |
|
||||
{ |
|
||||
public static IBinding FromMarkupExtensionContext( |
|
||||
IBinding binding, |
|
||||
IServiceProvider serviceProvider) |
|
||||
{ |
|
||||
var context = (ITypeDescriptorContext)serviceProvider; |
|
||||
var pvt = context.GetService<IProvideValueTarget>(); |
|
||||
|
|
||||
if (pvt.TargetObject is IControl) return binding; |
|
||||
|
|
||||
object anchor = GetDefaultAnchor(context); |
|
||||
|
|
||||
if (anchor == null) return binding; |
|
||||
|
|
||||
return new XamlBinding(binding, anchor); |
|
||||
} |
|
||||
|
|
||||
private static object GetDefaultAnchor(ITypeDescriptorContext context) |
|
||||
{ |
|
||||
object anchor = null; |
|
||||
|
|
||||
// The target is not a control, so we need to find an anchor that will let us look
|
|
||||
// up named controls and style resources. First look for the closest IControl in
|
|
||||
// the context.
|
|
||||
anchor = context.GetFirstAmbientValue<IControl>(); |
|
||||
|
|
||||
// If a control was not found, then try to find the highest-level style as the XAML
|
|
||||
// file could be a XAML file containing only styles.
|
|
||||
return anchor ?? |
|
||||
context.GetService<IRootObjectProvider>()?.RootObject as IStyle ?? |
|
||||
context.GetLastOrDefaultAmbientValue<IStyle>(); |
|
||||
} |
|
||||
|
|
||||
private XamlBinding(IBinding binding, object anchor) |
|
||||
{ |
|
||||
Value = binding; |
|
||||
|
|
||||
Anchor = new WeakReference(anchor); |
|
||||
} |
|
||||
|
|
||||
public WeakReference Anchor { get; } |
|
||||
|
|
||||
public IBinding Value { get; } |
|
||||
|
|
||||
public InstancedBinding Initiate(IAvaloniaObject target, AvaloniaProperty targetProperty, object anchor = null, bool enableDataValidation = false) |
|
||||
{ |
|
||||
return Value.Initiate(target, targetProperty, |
|
||||
anchor ?? Anchor.Target, enableDataValidation); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1 +1 @@ |
|||||
Subproject commit f226a516fe2bc191145c1fbf732f5a087f121a33 |
Subproject commit d50ae8335eb50d4b9606de6f5fa1cbbc78bfd72f |
||||
@ -0,0 +1,33 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Text; |
||||
|
using Avalonia.Platform; |
||||
|
using Avalonia.Rendering; |
||||
|
using MonoMac.Foundation; |
||||
|
|
||||
|
namespace Avalonia.MonoMac |
||||
|
{ |
||||
|
//TODO: Switch to using CVDisplayLink
|
||||
|
public class RenderLoop : IRenderLoop |
||||
|
{ |
||||
|
private readonly object _lock = new object(); |
||||
|
private readonly IDisposable _timer; |
||||
|
|
||||
|
public RenderLoop() |
||||
|
{ |
||||
|
_timer = AvaloniaLocator.Current.GetService<IRuntimePlatform>().StartSystemTimer(new TimeSpan(0, 0, 0, 0, 1000 / 60), |
||||
|
() => |
||||
|
{ |
||||
|
lock (_lock) |
||||
|
{ |
||||
|
using (new NSAutoreleasePool()) |
||||
|
{ |
||||
|
Tick?.Invoke(this, EventArgs.Empty); |
||||
|
} |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
public event EventHandler<EventArgs> Tick; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,277 @@ |
|||||
|
// 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 Xunit; |
||||
|
using System; |
||||
|
using System.Collections; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
|
||||
|
namespace Avalonia.Controls.UnitTests |
||||
|
{ |
||||
|
public class CalendarTests |
||||
|
{ |
||||
|
private static bool CompareDates(DateTime first, DateTime second) |
||||
|
{ |
||||
|
return first.Year == second.Year && |
||||
|
first.Month == second.Month && |
||||
|
first.Day == second.Day; |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void SelectedDatesChanged_Should_Fire_When_SelectedDate_Set() |
||||
|
{ |
||||
|
bool handled = false; |
||||
|
Calendar calendar = new Calendar(); |
||||
|
calendar.SelectionMode = CalendarSelectionMode.SingleDate; |
||||
|
calendar.SelectedDatesChanged += new EventHandler<SelectionChangedEventArgs>(delegate |
||||
|
{ |
||||
|
handled = true; |
||||
|
}); |
||||
|
DateTime value = new DateTime(2000, 10, 10); |
||||
|
calendar.SelectedDate = value; |
||||
|
Assert.True(handled); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void DisplayDateChanged_Should_Fire_When_DisplayDate_Set() |
||||
|
{ |
||||
|
bool handled = false; |
||||
|
Calendar calendar = new Calendar(); |
||||
|
calendar.SelectionMode = CalendarSelectionMode.SingleDate; |
||||
|
calendar.DisplayDateChanged += new EventHandler<CalendarDateChangedEventArgs>(delegate |
||||
|
{ |
||||
|
handled = true; |
||||
|
}); |
||||
|
DateTime value = new DateTime(2000, 10, 10); |
||||
|
calendar.DisplayDate = value; |
||||
|
Assert.True(handled); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Setting_Selected_Date_To_Blackout_Date_Should_Throw() |
||||
|
{ |
||||
|
Calendar calendar = new Calendar(); |
||||
|
calendar.BlackoutDates.AddDatesInPast(); |
||||
|
|
||||
|
Assert.ThrowsAny<ArgumentOutOfRangeException>( |
||||
|
() => calendar.SelectedDate = DateTime.Today.AddDays(-1)); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Setting_Selected_Date_To_Blackout_Date_Should_Throw_Range() |
||||
|
{ |
||||
|
Calendar calendar = new Calendar(); |
||||
|
calendar.BlackoutDates.Add(new CalendarDateRange(DateTime.Today, DateTime.Today.AddDays(10))); |
||||
|
|
||||
|
calendar.SelectedDate = DateTime.Today.AddDays(-1); |
||||
|
Assert.True(CompareDates(calendar.SelectedDate.Value, DateTime.Today.AddDays(-1))); |
||||
|
Assert.True(CompareDates(calendar.SelectedDate.Value, calendar.SelectedDates[0])); |
||||
|
|
||||
|
calendar.SelectedDate = DateTime.Today.AddDays(11); |
||||
|
Assert.True(CompareDates(calendar.SelectedDate.Value, DateTime.Today.AddDays(11))); |
||||
|
Assert.True(CompareDates(calendar.SelectedDate.Value, calendar.SelectedDates[0])); |
||||
|
|
||||
|
Assert.ThrowsAny<ArgumentOutOfRangeException>( |
||||
|
() => calendar.SelectedDate = DateTime.Today.AddDays(5)); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Adding_Blackout_Dates_Containing_Selected_Date_Should_Throw() |
||||
|
{ |
||||
|
Calendar calendar = new Calendar(); |
||||
|
calendar.SelectedDate = DateTime.Today.AddDays(5); |
||||
|
|
||||
|
Assert.ThrowsAny<ArgumentOutOfRangeException>( |
||||
|
() => calendar.BlackoutDates.Add(new CalendarDateRange(DateTime.Today, DateTime.Today.AddDays(10)))); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void DisplayDateStartEnd_Should_Constrain_Display_Date() |
||||
|
{ |
||||
|
Calendar calendar = new Calendar(); |
||||
|
calendar.SelectionMode = CalendarSelectionMode.SingleDate; |
||||
|
calendar.DisplayDateStart = new DateTime(2005, 12, 30); |
||||
|
|
||||
|
DateTime value = new DateTime(2005, 12, 15); |
||||
|
calendar.DisplayDate = value; |
||||
|
Assert.True(CompareDates(calendar.DisplayDate, calendar.DisplayDateStart.Value)); |
||||
|
|
||||
|
value = new DateTime(2005, 12, 30); |
||||
|
calendar.DisplayDate = value; |
||||
|
Assert.True(CompareDates(calendar.DisplayDate, value)); |
||||
|
|
||||
|
value = DateTime.MaxValue; |
||||
|
calendar.DisplayDate = value; |
||||
|
Assert.True(CompareDates(calendar.DisplayDate, value)); |
||||
|
|
||||
|
calendar.DisplayDateEnd = new DateTime(2010, 12, 30); |
||||
|
Assert.True(CompareDates(calendar.DisplayDate, calendar.DisplayDateEnd.Value)); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Setting_DisplayDateEnd_Should_Alter_DispalyDate_And_DisplayDateStart() |
||||
|
{ |
||||
|
Calendar calendar = new Calendar(); |
||||
|
DateTime value = new DateTime(2000, 1, 30); |
||||
|
|
||||
|
calendar.DisplayDate = value; |
||||
|
calendar.DisplayDateEnd = value; |
||||
|
calendar.DisplayDateStart = value; |
||||
|
Assert.True(CompareDates(calendar.DisplayDateStart.Value, value)); |
||||
|
Assert.True(CompareDates(calendar.DisplayDateEnd.Value, value)); |
||||
|
|
||||
|
value = value.AddMonths(2); |
||||
|
calendar.DisplayDateStart = value; |
||||
|
Assert.True(CompareDates(calendar.DisplayDateStart.Value, value)); |
||||
|
Assert.True(CompareDates(calendar.DisplayDateEnd.Value, value)); |
||||
|
Assert.True(CompareDates(calendar.DisplayDate, value)); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Display_Date_Range_End_Will_Contain_SelectedDate() |
||||
|
{ |
||||
|
Calendar calendar = new Calendar(); |
||||
|
calendar.SelectionMode = CalendarSelectionMode.SingleDate; |
||||
|
|
||||
|
calendar.SelectedDate = DateTime.MaxValue; |
||||
|
Assert.True(CompareDates((DateTime)calendar.SelectedDate, DateTime.MaxValue)); |
||||
|
|
||||
|
calendar.DisplayDateEnd = DateTime.MaxValue.AddDays(-1); |
||||
|
Assert.True(CompareDates((DateTime)calendar.DisplayDateEnd, DateTime.MaxValue)); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
/// <summary>
|
||||
|
/// The days added to the SelectedDates collection.
|
||||
|
/// </summary>
|
||||
|
private IList<object> _selectedDatesChangedAddedDays; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// The days removed from the SelectedDates collection.
|
||||
|
/// </summary>
|
||||
|
private IList<object> _selectedDateChangedRemovedDays; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// The number of times the SelectedDatesChanged event has been fired.
|
||||
|
/// </summary>
|
||||
|
private int _selectedDatesChangedCount; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Handle the SelectedDatesChanged event.
|
||||
|
/// </summary>
|
||||
|
/// <param name="sender">The calendar.</param>
|
||||
|
/// <param name="e">Event arguments.</param>
|
||||
|
private void OnSelectedDatesChanged(object sender, SelectionChangedEventArgs e) |
||||
|
{ |
||||
|
_selectedDatesChangedAddedDays = |
||||
|
e.AddedItems |
||||
|
.Cast<object>() |
||||
|
.ToList(); |
||||
|
_selectedDateChangedRemovedDays = |
||||
|
e.RemovedItems |
||||
|
.Cast<object>() |
||||
|
.ToList(); |
||||
|
_selectedDatesChangedCount++; |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Clear the variables used to track the SelectedDatesChanged event.
|
||||
|
/// </summary>
|
||||
|
private void ResetSelectedDatesChanged() |
||||
|
{ |
||||
|
if (_selectedDatesChangedAddedDays != null) |
||||
|
{ |
||||
|
_selectedDatesChangedAddedDays.Clear(); |
||||
|
} |
||||
|
|
||||
|
if (_selectedDateChangedRemovedDays != null) |
||||
|
{ |
||||
|
_selectedDateChangedRemovedDays.Clear(); |
||||
|
} |
||||
|
|
||||
|
_selectedDatesChangedCount = 0; |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void SingleDate_Selection_Behavior() |
||||
|
{ |
||||
|
ResetSelectedDatesChanged(); |
||||
|
Calendar calendar = new Calendar(); |
||||
|
calendar.SelectedDatesChanged += new EventHandler<SelectionChangedEventArgs>(OnSelectedDatesChanged); |
||||
|
calendar.SelectionMode = CalendarSelectionMode.SingleDate; |
||||
|
calendar.SelectedDate = DateTime.Today; |
||||
|
Assert.True(CompareDates(calendar.SelectedDate.Value, DateTime.Today)); |
||||
|
Assert.True(calendar.SelectedDates.Count == 1); |
||||
|
Assert.True(CompareDates(calendar.SelectedDates[0], DateTime.Today)); |
||||
|
Assert.True(_selectedDatesChangedCount == 1); |
||||
|
Assert.True(_selectedDatesChangedAddedDays.Count == 1); |
||||
|
Assert.True(_selectedDateChangedRemovedDays.Count == 0); |
||||
|
ResetSelectedDatesChanged(); |
||||
|
|
||||
|
calendar.SelectedDate = DateTime.Today; |
||||
|
Assert.True(CompareDates(calendar.SelectedDate.Value, DateTime.Today)); |
||||
|
Assert.True(calendar.SelectedDates.Count == 1); |
||||
|
Assert.True(CompareDates(calendar.SelectedDates[0], DateTime.Today)); |
||||
|
Assert.True(_selectedDatesChangedCount == 0); |
||||
|
|
||||
|
calendar.ClearValue(Calendar.SelectedDateProperty); |
||||
|
|
||||
|
calendar.SelectionMode = CalendarSelectionMode.None; |
||||
|
Assert.True(calendar.SelectedDates.Count == 0); |
||||
|
Assert.Null(calendar.SelectedDate); |
||||
|
|
||||
|
calendar.SelectionMode = CalendarSelectionMode.SingleDate; |
||||
|
|
||||
|
calendar.SelectedDates.Add(DateTime.Today.AddDays(1)); |
||||
|
Assert.True(CompareDates(calendar.SelectedDate.Value, DateTime.Today.AddDays(1))); |
||||
|
Assert.True(calendar.SelectedDates.Count == 1); |
||||
|
|
||||
|
Assert.ThrowsAny<InvalidOperationException>( |
||||
|
() => calendar.SelectedDates.Add(DateTime.Today.AddDays(2))); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void SingleRange_Selection_Behavior() |
||||
|
{ |
||||
|
ResetSelectedDatesChanged(); |
||||
|
Calendar calendar = new Calendar(); |
||||
|
calendar.SelectedDatesChanged += new EventHandler<SelectionChangedEventArgs>(OnSelectedDatesChanged); |
||||
|
calendar.SelectionMode = CalendarSelectionMode.SingleRange; |
||||
|
calendar.SelectedDate = DateTime.Today; |
||||
|
Assert.True(CompareDates(calendar.SelectedDate.Value, DateTime.Today)); |
||||
|
Assert.True(calendar.SelectedDates.Count == 1); |
||||
|
Assert.True(CompareDates(calendar.SelectedDates[0], DateTime.Today)); |
||||
|
Assert.True(_selectedDatesChangedCount == 1); |
||||
|
Assert.True(_selectedDatesChangedAddedDays.Count == 1); |
||||
|
Assert.True(_selectedDateChangedRemovedDays.Count == 0); |
||||
|
ResetSelectedDatesChanged(); |
||||
|
|
||||
|
calendar.SelectedDates.Clear(); |
||||
|
Assert.Null(calendar.SelectedDate); |
||||
|
ResetSelectedDatesChanged(); |
||||
|
|
||||
|
calendar.SelectedDates.AddRange(DateTime.Today, DateTime.Today.AddDays(10)); |
||||
|
Assert.True(CompareDates(calendar.SelectedDate.Value, DateTime.Today)); |
||||
|
Assert.True(calendar.SelectedDates.Count == 11); |
||||
|
ResetSelectedDatesChanged(); |
||||
|
|
||||
|
calendar.SelectedDates.AddRange(DateTime.Today, DateTime.Today.AddDays(10)); |
||||
|
Assert.True(calendar.SelectedDates.Count == 11); |
||||
|
Assert.True(_selectedDatesChangedCount == 0); |
||||
|
ResetSelectedDatesChanged(); |
||||
|
|
||||
|
calendar.SelectedDates.AddRange(DateTime.Today.AddDays(-20), DateTime.Today); |
||||
|
Assert.True(CompareDates(calendar.SelectedDate.Value, DateTime.Today.AddDays(-20))); |
||||
|
Assert.True(calendar.SelectedDates.Count == 21); |
||||
|
Assert.True(_selectedDatesChangedCount == 1); |
||||
|
Assert.True(_selectedDatesChangedAddedDays.Count == 21); |
||||
|
Assert.True(_selectedDateChangedRemovedDays.Count == 11); |
||||
|
ResetSelectedDatesChanged(); |
||||
|
|
||||
|
calendar.SelectedDates.Add(DateTime.Today.AddDays(100)); |
||||
|
Assert.True(CompareDates(calendar.SelectedDate.Value, DateTime.Today.AddDays(100))); |
||||
|
Assert.True(calendar.SelectedDates.Count == 1); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue