diff --git a/src/Avalonia.Base/AttachedProperty.cs b/src/Avalonia.Base/AttachedProperty.cs index 31b6cad8abc..4a09f2a80af 100644 --- a/src/Avalonia.Base/AttachedProperty.cs +++ b/src/Avalonia.Base/AttachedProperty.cs @@ -32,9 +32,14 @@ public AttachedProperty( /// /// The owner type. /// The property. - public new AttachedProperty AddOwner() where TOwner : AvaloniaObject + public new AttachedProperty AddOwner(StyledPropertyMetadata? metadata = null) where TOwner : AvaloniaObject { AvaloniaPropertyRegistry.Instance.Register(typeof(TOwner), this); + if (metadata != null) + { + OverrideMetadata(metadata); + } + return this; } } diff --git a/src/Avalonia.Base/Input/GestureRecognizers/GestureRecognizerCollection.cs b/src/Avalonia.Base/Input/GestureRecognizers/GestureRecognizerCollection.cs index a202d6b5bcf..3b9b2d0de61 100644 --- a/src/Avalonia.Base/Input/GestureRecognizers/GestureRecognizerCollection.cs +++ b/src/Avalonia.Base/Input/GestureRecognizers/GestureRecognizerCollection.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using Avalonia.Controls; using Avalonia.LogicalTree; -using Avalonia.Styling; +using Avalonia.Reactive; namespace Avalonia.Input.GestureRecognizers { @@ -11,13 +11,13 @@ public class GestureRecognizerCollection : IReadOnlyCollection? _recognizers; private Dictionary? _pointerGrabs; - - + + public GestureRecognizerCollection(IInputElement inputElement) { _inputElement = inputElement; } - + public void Add(IGestureRecognizer recognizer) { if (_recognizers == null) @@ -31,14 +31,13 @@ public void Add(IGestureRecognizer recognizer) recognizer.Initialize(_inputElement, this); // Hacks to make bindings work - + if (_inputElement is ILogical logicalParent && recognizer is ISetLogicalParent logical) { logical.SetParent(logicalParent); if (recognizer is StyledElement styleableRecognizer && _inputElement is StyledElement styleableParent) - styleableRecognizer.Bind(StyledElement.TemplatedParentProperty, - styleableParent.GetObservable(StyledElement.TemplatedParentProperty)); + styleableParent.GetObservable(StyledElement.TemplatedParentProperty).Subscribe(parent => styleableRecognizer.TemplatedParent = parent); } } @@ -58,7 +57,7 @@ internal bool HandlePointerPressed(PointerPressedEventArgs e) return false; foreach (var r in _recognizers) { - if(e.Handled) + if (e.Handled) break; r.PointerPressed(e); } diff --git a/src/Avalonia.Base/Input/GestureRecognizers/PullGestureRecognizer.cs b/src/Avalonia.Base/Input/GestureRecognizers/PullGestureRecognizer.cs index 991694cc60c..6784677520e 100644 --- a/src/Avalonia.Base/Input/GestureRecognizers/PullGestureRecognizer.cs +++ b/src/Avalonia.Base/Input/GestureRecognizers/PullGestureRecognizer.cs @@ -13,22 +13,18 @@ public class PullGestureRecognizer : StyledElement, IGestureRecognizer private Point _initialPosition; private int _gestureId; private IPointer? _tracking; - private PullDirection _pullDirection; private bool _pullInProgress; /// /// Defines the property. /// - public static readonly DirectProperty PullDirectionProperty = - AvaloniaProperty.RegisterDirect( - nameof(PullDirection), - o => o.PullDirection, - (o, v) => o.PullDirection = v); + public static readonly StyledProperty PullDirectionProperty = + AvaloniaProperty.Register(nameof(PullDirection)); public PullDirection PullDirection { - get => _pullDirection; - set => SetAndRaise(PullDirectionProperty, ref _pullDirection, value); + get => GetValue(PullDirectionProperty); + set => SetValue(PullDirectionProperty, value); } public PullGestureRecognizer(PullDirection pullDirection) diff --git a/src/Avalonia.Base/Input/GestureRecognizers/ScrollGestureRecognizer.cs b/src/Avalonia.Base/Input/GestureRecognizers/ScrollGestureRecognizer.cs index 7c1ee13eed8..1ad2f292ca1 100644 --- a/src/Avalonia.Base/Input/GestureRecognizers/ScrollGestureRecognizer.cs +++ b/src/Avalonia.Base/Input/GestureRecognizers/ScrollGestureRecognizer.cs @@ -17,61 +17,45 @@ public class ScrollGestureRecognizer private IPointer? _tracking; private IInputElement? _target; private IGestureRecognizerActionsDispatcher? _actions; - private bool _canHorizontallyScroll; - private bool _canVerticallyScroll; private int _gestureId; - private int _scrollStartDistance = 30; private Point _pointerPressedPoint; private VelocityTracker? _velocityTracker; // Movement per second private Vector _inertia; private ulong? _lastMoveTimestamp; - private bool _isScrollInertiaEnabled; /// /// Defines the property. /// - public static readonly DirectProperty CanHorizontallyScrollProperty = - AvaloniaProperty.RegisterDirect( - nameof(CanHorizontallyScroll), - o => o.CanHorizontallyScroll, - (o, v) => o.CanHorizontallyScroll = v); + public static readonly StyledProperty CanHorizontallyScrollProperty = + AvaloniaProperty.Register(nameof(CanHorizontallyScroll)); /// /// Defines the property. /// - public static readonly DirectProperty CanVerticallyScrollProperty = - AvaloniaProperty.RegisterDirect( - nameof(CanVerticallyScroll), - o => o.CanVerticallyScroll, - (o, v) => o.CanVerticallyScroll = v); + public static readonly StyledProperty CanVerticallyScrollProperty = + AvaloniaProperty.Register(nameof(CanVerticallyScroll)); /// /// Defines the property. /// - public static readonly DirectProperty IsScrollInertiaEnabledProperty = - AvaloniaProperty.RegisterDirect( - nameof(IsScrollInertiaEnabled), - o => o.IsScrollInertiaEnabled, - (o, v) => o.IsScrollInertiaEnabled = v); + public static readonly StyledProperty IsScrollInertiaEnabledProperty = + AvaloniaProperty.Register(nameof(IsScrollInertiaEnabled)); /// /// Defines the property. /// - public static readonly DirectProperty ScrollStartDistanceProperty = - AvaloniaProperty.RegisterDirect( - nameof(ScrollStartDistance), - o => o.ScrollStartDistance, - (o, v) => o.ScrollStartDistance = v); + public static readonly StyledProperty ScrollStartDistanceProperty = + AvaloniaProperty.Register(nameof(ScrollStartDistance), 30); /// /// Gets or sets a value indicating whether the content can be scrolled horizontally. /// public bool CanHorizontallyScroll { - get => _canHorizontallyScroll; - set => SetAndRaise(CanHorizontallyScrollProperty, ref _canHorizontallyScroll, value); + get => GetValue(CanHorizontallyScrollProperty); + set => SetValue(CanHorizontallyScrollProperty, value); } /// @@ -79,8 +63,8 @@ public bool CanHorizontallyScroll /// public bool CanVerticallyScroll { - get => _canVerticallyScroll; - set => SetAndRaise(CanVerticallyScrollProperty, ref _canVerticallyScroll, value); + get => GetValue(CanVerticallyScrollProperty); + set => SetValue(CanVerticallyScrollProperty, value); } /// @@ -88,8 +72,8 @@ public bool CanVerticallyScroll /// public bool IsScrollInertiaEnabled { - get => _isScrollInertiaEnabled; - set => SetAndRaise(IsScrollInertiaEnabledProperty, ref _isScrollInertiaEnabled, value); + get => GetValue(IsScrollInertiaEnabledProperty); + set => SetValue(IsScrollInertiaEnabledProperty, value); } /// @@ -97,8 +81,8 @@ public bool IsScrollInertiaEnabled /// public int ScrollStartDistance { - get => _scrollStartDistance; - set => SetAndRaise(ScrollStartDistanceProperty, ref _scrollStartDistance, value); + get => GetValue(ScrollStartDistanceProperty); + set => SetValue(ScrollStartDistanceProperty, value); } @@ -137,8 +121,8 @@ public void PointerMoved(PointerEventArgs e) // Correct _trackedRootPoint with ScrollStartDistance, so scrolling does not start with a skip of ScrollStartDistance _trackedRootPoint = new Point( - _trackedRootPoint.X - (_trackedRootPoint.X >= rootPoint.X ? _scrollStartDistance : -_scrollStartDistance), - _trackedRootPoint.Y - (_trackedRootPoint.Y >= rootPoint.Y ? _scrollStartDistance : -_scrollStartDistance)); + _trackedRootPoint.X - (_trackedRootPoint.X >= rootPoint.X ? ScrollStartDistance : -ScrollStartDistance), + _trackedRootPoint.Y - (_trackedRootPoint.Y >= rootPoint.Y ? ScrollStartDistance : -ScrollStartDistance)); _actions!.Capture(e.Pointer, this); } diff --git a/src/Avalonia.Base/Media/Imaging/CroppedBitmap.cs b/src/Avalonia.Base/Media/Imaging/CroppedBitmap.cs index 525a543b702..8e57f9a9025 100644 --- a/src/Avalonia.Base/Media/Imaging/CroppedBitmap.cs +++ b/src/Avalonia.Base/Media/Imaging/CroppedBitmap.cs @@ -48,8 +48,6 @@ public PixelRect SourceRect public CroppedBitmap() { - Source = null; - SourceRect = default; } public CroppedBitmap(IImage source, PixelRect sourceRect) diff --git a/src/Avalonia.Base/StyledElement.cs b/src/Avalonia.Base/StyledElement.cs index cbdf3c3c1e2..b51093b40c9 100644 --- a/src/Avalonia.Base/StyledElement.cs +++ b/src/Avalonia.Base/StyledElement.cs @@ -67,8 +67,7 @@ public class StyledElement : Animatable, public static readonly DirectProperty TemplatedParentProperty = AvaloniaProperty.RegisterDirect( nameof(TemplatedParent), - o => o.TemplatedParent, - (o ,v) => o.TemplatedParent = v); + o => o.TemplatedParent); /// /// Defines the property. diff --git a/src/Avalonia.Base/StyledProperty.cs b/src/Avalonia.Base/StyledProperty.cs index 8695918c185..50528400131 100644 --- a/src/Avalonia.Base/StyledProperty.cs +++ b/src/Avalonia.Base/StyledProperty.cs @@ -56,9 +56,14 @@ public StyledProperty( /// /// The type of the additional owner. /// The property. - public StyledProperty AddOwner() where TOwner : AvaloniaObject + public StyledProperty AddOwner(StyledPropertyMetadata? metadata = null) where TOwner : AvaloniaObject { AvaloniaPropertyRegistry.Instance.Register(typeof(TOwner), this); + if (metadata != null) + { + OverrideMetadata(metadata); + } + return this; } diff --git a/src/Avalonia.Controls/Button.cs b/src/Avalonia.Controls/Button.cs index 1ec6f8dabc7..f48d7a7cc1d 100644 --- a/src/Avalonia.Controls/Button.cs +++ b/src/Avalonia.Controls/Button.cs @@ -1,11 +1,9 @@ using System; -using System.Diagnostics; using System.Linq; using System.Windows.Input; using Avalonia.Automation.Peers; using Avalonia.Controls.Metadata; using Avalonia.Controls.Primitives; -using Avalonia.Controls.Templates; using Avalonia.Data; using Avalonia.Input; using Avalonia.Interactivity; @@ -48,9 +46,8 @@ public class Button : ContentControl, ICommandSource, IClickableControl /// /// Defines the property. /// - public static readonly DirectProperty CommandProperty = - AvaloniaProperty.RegisterDirect(nameof(Command), - button => button.Command, (button, command) => button.Command = command, enableDataValidation: true); + public static readonly StyledProperty CommandProperty = + AvaloniaProperty.Register(nameof(Command), enableDataValidation: true); /// /// Defines the property. @@ -85,8 +82,8 @@ public class Button : ContentControl, ICommandSource, IClickableControl /// /// Defines the property. /// - public static readonly StyledProperty IsPressedProperty = - AvaloniaProperty.Register(nameof(IsPressed)); + public static readonly DirectProperty IsPressedProperty = + AvaloniaProperty.RegisterDirect(nameof(IsPressed), b => b.IsPressed); /// /// Defines the property @@ -94,10 +91,10 @@ public class Button : ContentControl, ICommandSource, IClickableControl public static readonly StyledProperty FlyoutProperty = AvaloniaProperty.Register(nameof(Flyout)); - private ICommand? _command; private bool _commandCanExecute = true; private KeyGesture? _hotkey; private bool _isFlyoutOpen = false; + private bool _isPressed = false; /// /// Initializes static members of the class. @@ -138,8 +135,8 @@ public ClickMode ClickMode /// public ICommand? Command { - get => _command; - set => SetAndRaise(CommandProperty, ref _command, value); + get => GetValue(CommandProperty); + set => SetValue(CommandProperty, value); } /// @@ -185,8 +182,8 @@ public bool IsCancel /// public bool IsPressed { - get => GetValue(IsPressedProperty); - private set => SetValue(IsPressedProperty, value); + get => _isPressed; + private set => SetAndRaise(IsPressedProperty, ref _isPressed, value); } /// @@ -248,7 +245,7 @@ protected override void OnAttachedToLogicalTree(LogicalTreeAttachmentEventArgs e { if (_hotkey != null) // Control attached again, set Hotkey to create a hotkey manager for this control { - HotKey = _hotkey; + SetCurrentValue(HotKeyProperty, _hotkey); } base.OnAttachedToLogicalTree(e); @@ -267,7 +264,7 @@ protected override void OnDetachedFromLogicalTree(LogicalTreeAttachmentEventArgs if (HotKey != null) { _hotkey = HotKey; - HotKey = null; + SetCurrentValue(HotKeyProperty, null); } base.OnDetachedFromLogicalTree(e); @@ -291,17 +288,17 @@ protected override void OnKeyDown(KeyEventArgs e) break; case Key.Space: - { - if (ClickMode == ClickMode.Press) { - OnClick(); + if (ClickMode == ClickMode.Press) + { + OnClick(); + } + + IsPressed = true; + e.Handled = true; + break; } - IsPressed = true; - e.Handled = true; - break; - } - case Key.Escape when Flyout != null: // If Flyout doesn't have focusable content, close the flyout here CloseFlyout(); @@ -592,7 +589,7 @@ private void UnregisterFlyoutEvents(FlyoutBase? flyout) { flyout.Opened -= Flyout_Opened; flyout.Closed -= Flyout_Closed; - } + } } /// @@ -671,7 +668,7 @@ private void UpdatePseudoClasses() void ICommandSource.CanExecuteChanged(object sender, EventArgs e) => this.CanExecuteChanged(sender, e); void IClickableControl.RaiseClick() => OnClick(); - + /// /// Event handler for when the button's flyout is opened. /// diff --git a/src/Avalonia.Controls/Calendar/Calendar.cs b/src/Avalonia.Controls/Calendar/Calendar.cs index 3300292857e..10aadfa759f 100644 --- a/src/Avalonia.Controls/Calendar/Calendar.cs +++ b/src/Avalonia.Controls/Calendar/Calendar.cs @@ -232,14 +232,9 @@ public class Calendar : TemplatedControl internal const int RowsPerYear = 3; internal const int ColumnsPerYear = 4; - private DateTime? _selectedDate; private DateTime _selectedMonth; private DateTime _selectedYear; - private DateTime _displayDate = DateTime.Today; - private DateTime? _displayDateStart; - private DateTime? _displayDateEnd; - private bool _isShiftPressed; private bool _displayDateIsChanging; @@ -396,13 +391,13 @@ private void OnDisplayModePropertyChanged(AvaloniaPropertyChangedEventArgs e) } case CalendarMode.Year: { - DisplayDate = SelectedMonth; + SetCurrentValue(DisplayDateProperty, SelectedMonth); SelectedYear = SelectedMonth; break; } case CalendarMode.Decade: { - DisplayDate = SelectedYear; + SetCurrentValue(DisplayDateProperty, SelectedYear); SelectedMonth = SelectedYear; break; } @@ -472,7 +467,7 @@ private void OnSelectionModeChanged(AvaloniaPropertyChangedEventArgs e) if (IsValidSelectionMode(e.NewValue!)) { _displayDateIsChanging = true; - SelectedDate = null; + SetCurrentValue(SelectedDateProperty, null); _displayDateIsChanging = false; SelectedDates.Clear(); } @@ -497,11 +492,8 @@ private static bool IsValidSelectionMode(object value) || mode == CalendarSelectionMode.None; } - public static readonly DirectProperty SelectedDateProperty = - AvaloniaProperty.RegisterDirect( - nameof(SelectedDate), - o => o.SelectedDate, - (o, v) => o.SelectedDate = v, + public static readonly StyledProperty SelectedDateProperty = + AvaloniaProperty.Register(nameof(SelectedDate), defaultBindingMode: BindingMode.TwoWay); /// @@ -529,8 +521,8 @@ private static bool IsValidSelectionMode(object value) /// public DateTime? SelectedDate { - get { return _selectedDate; } - set { SetAndRaise(SelectedDateProperty, ref _selectedDate, value); } + get => GetValue(SelectedDateProperty); + set => SetValue(SelectedDateProperty, value); } private void OnSelectedDateChanged(AvaloniaPropertyChangedEventArgs e) { @@ -726,11 +718,8 @@ internal DateTime SelectedYear } } - public static readonly DirectProperty DisplayDateProperty = - AvaloniaProperty.RegisterDirect( - nameof(DisplayDate), - o => o.DisplayDate, - (o, v) => o.DisplayDate = v, + public static readonly StyledProperty DisplayDateProperty = + AvaloniaProperty.Register(nameof(DisplayDate), defaultBindingMode: BindingMode.TwoWay); /// @@ -760,8 +749,8 @@ internal DateTime SelectedYear /// public DateTime DisplayDate { - get { return _displayDate; } - set { SetAndRaise(DisplayDateProperty, ref _displayDate, value); } + get => GetValue(DisplayDateProperty); + set => SetValue(DisplayDateProperty, value); } internal DateTime DisplayDateInternal { get; private set; } @@ -796,11 +785,8 @@ private void OnDisplayDate(CalendarDateChangedEventArgs e) DisplayDateChanged?.Invoke(this, e); } - public static readonly DirectProperty DisplayDateStartProperty = - AvaloniaProperty.RegisterDirect( - nameof(DisplayDateStart), - o => o.DisplayDateStart, - (o, v) => o.DisplayDateStart = v, + public static readonly StyledProperty DisplayDateStartProperty = + AvaloniaProperty.Register(nameof(DisplayDateStart), defaultBindingMode: BindingMode.TwoWay); /// /// Gets or sets the first date to be displayed. @@ -814,8 +800,8 @@ private void OnDisplayDate(CalendarDateChangedEventArgs e) /// public DateTime? DisplayDateStart { - get { return _displayDateStart; } - set { SetAndRaise(DisplayDateStartProperty, ref _displayDateStart, value); } + get => GetValue(DisplayDateStartProperty); + set => SetValue(DisplayDateStartProperty, value); } private void OnDisplayDateStartChanged(AvaloniaPropertyChangedEventArgs e) { @@ -831,7 +817,7 @@ private void OnDisplayDateStartChanged(AvaloniaPropertyChangedEventArgs e) if (selectedDateMin.HasValue && DateTime.Compare(selectedDateMin.Value, newValue.Value) < 0) { - DisplayDateStart = selectedDateMin.Value; + SetCurrentValue(DisplayDateStartProperty, selectedDateMin.Value); return; } @@ -839,14 +825,14 @@ private void OnDisplayDateStartChanged(AvaloniaPropertyChangedEventArgs e) // DisplayDateEnd = DisplayDateStart if (DateTime.Compare(newValue.Value, DisplayDateRangeEnd) > 0) { - DisplayDateEnd = DisplayDateStart; + SetCurrentValue(DisplayDateEndProperty, DisplayDateStart); } // If DisplayDate < DisplayDateStart, // DisplayDate = DisplayDateStart if (DateTimeHelper.CompareYearMonth(newValue.Value, DisplayDateInternal) > 0) { - DisplayDate = newValue.Value; + SetCurrentValue(DisplayDateProperty, newValue.Value); } } UpdateMonths(); @@ -905,11 +891,8 @@ internal DateTime DisplayDateRangeStart get { return DisplayDateStart.GetValueOrDefault(DateTime.MinValue); } } - public static readonly DirectProperty DisplayDateEndProperty = - AvaloniaProperty.RegisterDirect( - nameof(DisplayDateEnd), - o => o.DisplayDateEnd, - (o, v) => o.DisplayDateEnd = v, + public static readonly StyledProperty DisplayDateEndProperty = + AvaloniaProperty.Register(nameof(DisplayDateEnd), defaultBindingMode: BindingMode.TwoWay); /// @@ -924,8 +907,8 @@ internal DateTime DisplayDateRangeStart /// public DateTime? DisplayDateEnd { - get { return _displayDateEnd; } - set { SetAndRaise(DisplayDateEndProperty, ref _displayDateEnd, value); } + get => GetValue(DisplayDateEndProperty); + set => SetValue(DisplayDateEndProperty, value); } private void OnDisplayDateEndChanged(AvaloniaPropertyChangedEventArgs e) @@ -942,7 +925,7 @@ private void OnDisplayDateEndChanged(AvaloniaPropertyChangedEventArgs e) if (selectedDateMax.HasValue && DateTime.Compare(selectedDateMax.Value, newValue.Value) > 0) { - DisplayDateEnd = selectedDateMax.Value; + SetCurrentValue(DisplayDateEndProperty, selectedDateMax.Value); return; } @@ -950,7 +933,7 @@ private void OnDisplayDateEndChanged(AvaloniaPropertyChangedEventArgs e) // DisplayDateEnd = DisplayDateStart if (DateTime.Compare(newValue.Value, DisplayDateRangeStart) < 0) { - DisplayDateEnd = DisplayDateStart; + SetCurrentValue(DisplayDateEndProperty, DisplayDateStart); return; } @@ -958,7 +941,7 @@ private void OnDisplayDateEndChanged(AvaloniaPropertyChangedEventArgs e) // DisplayDate = DisplayDateEnd if (DateTimeHelper.CompareYearMonth(newValue.Value, DisplayDateInternal) < 0) { - DisplayDate = newValue.Value; + SetCurrentValue(DisplayDateProperty, newValue.Value); } } UpdateMonths(); @@ -1284,7 +1267,7 @@ internal void OnPreviousClick() { LastSelectedDate = d.Value; } - DisplayDate = d.Value; + SetCurrentValue(DisplayDateProperty, d.Value); } } else @@ -1332,7 +1315,7 @@ internal void OnNextClick() { LastSelectedDate = d.Value; } - DisplayDate = d.Value; + SetCurrentValue(DisplayDateProperty, d.Value); } } else @@ -1719,7 +1702,7 @@ internal void ProcessUpKey(bool ctrl, bool shift) if (ctrl) { SelectedMonth = DisplayDateInternal; - DisplayMode = CalendarMode.Year; + SetCurrentValue(DisplayModeProperty, CalendarMode.Year); } else { @@ -1733,7 +1716,7 @@ internal void ProcessUpKey(bool ctrl, bool shift) if (ctrl) { SelectedYear = SelectedMonth; - DisplayMode = CalendarMode.Decade; + SetCurrentValue(DisplayModeProperty, CalendarMode.Decade); } else { @@ -1770,8 +1753,8 @@ internal void ProcessDownKey(bool ctrl, bool shift) { if (ctrl) { - DisplayDate = SelectedMonth; - DisplayMode = CalendarMode.Month; + SetCurrentValue(DisplayDateProperty, SelectedMonth); + SetCurrentValue(DisplayModeProperty, CalendarMode.Month); } else { @@ -1785,7 +1768,7 @@ internal void ProcessDownKey(bool ctrl, bool shift) if (ctrl) { SelectedMonth = SelectedYear; - DisplayMode = CalendarMode.Year; + SetCurrentValue(DisplayModeProperty, CalendarMode.Year); } else { @@ -1850,14 +1833,14 @@ private bool ProcessEnterKey() { case CalendarMode.Year: { - DisplayDate = SelectedMonth; - DisplayMode = CalendarMode.Month; + SetCurrentValue(DisplayDateProperty, SelectedMonth); + SetCurrentValue(DisplayModeProperty, CalendarMode.Month); return true; } case CalendarMode.Decade: { SelectedMonth = SelectedYear; - DisplayMode = CalendarMode.Year; + SetCurrentValue(DisplayModeProperty, CalendarMode.Year); return true; } } @@ -2103,7 +2086,8 @@ static Calendar() /// public Calendar() { - UpdateDisplayDate(this, this.DisplayDate, DateTime.MinValue); + SetCurrentValue(DisplayDateProperty, DateTime.Today); + UpdateDisplayDate(this, DisplayDate, DateTime.MinValue); BlackoutDates = new CalendarBlackoutDatesCollection(this); SelectedDates = new SelectedDatesCollection(this); RemovedItems = new Collection(); diff --git a/src/Avalonia.Controls/Calendar/CalendarItem.cs b/src/Avalonia.Controls/Calendar/CalendarItem.cs index 3d436b4485b..2e3f1f96ce8 100644 --- a/src/Avalonia.Controls/Calendar/CalendarItem.cs +++ b/src/Avalonia.Controls/Calendar/CalendarItem.cs @@ -41,7 +41,6 @@ public sealed class CalendarItem : TemplatedControl private Button? _headerButton; private Button? _nextButton; private Button? _previousButton; - private ITemplate? _dayTitleTemplate; private DateTime _currentMonth; private bool _isMouseLeftButtonDown; @@ -61,17 +60,15 @@ public IBrush? HeaderBackground set { SetValue(HeaderBackgroundProperty, value); } } - public static readonly DirectProperty?> DayTitleTemplateProperty = - AvaloniaProperty.RegisterDirect?>( + public static readonly StyledProperty?> DayTitleTemplateProperty = + AvaloniaProperty.Register?>( nameof(DayTitleTemplate), - o => o.DayTitleTemplate, - (o,v) => o.DayTitleTemplate = v, defaultBindingMode: BindingMode.OneTime); public ITemplate? DayTitleTemplate { - get { return _dayTitleTemplate; } - set { SetAndRaise(DayTitleTemplateProperty, ref _dayTitleTemplate, value); } + get => GetValue(DayTitleTemplateProperty); + set => SetValue(DayTitleTemplateProperty, value); } /// @@ -176,9 +173,8 @@ private void PopulateGrids() for (int i = 0; i < Calendar.RowsPerMonth; i++) { - if (_dayTitleTemplate != null) + if (DayTitleTemplate?.Build() is Control cell) { - var cell = _dayTitleTemplate.Build(); cell.DataContext = string.Empty; cell.SetValue(Grid.RowProperty, 0); cell.SetValue(Grid.ColumnProperty, i); diff --git a/src/Avalonia.Controls/CalendarDatePicker/CalendarDatePicker.Properties.cs b/src/Avalonia.Controls/CalendarDatePicker/CalendarDatePicker.Properties.cs index 6c2356b411c..1454b4ab6cc 100644 --- a/src/Avalonia.Controls/CalendarDatePicker/CalendarDatePicker.Properties.cs +++ b/src/Avalonia.Controls/CalendarDatePicker/CalendarDatePicker.Properties.cs @@ -11,29 +11,22 @@ public partial class CalendarDatePicker /// /// Defines the property. /// - public static readonly DirectProperty DisplayDateProperty = - AvaloniaProperty.RegisterDirect( - nameof(DisplayDate), - o => o.DisplayDate, - (o, v) => o.DisplayDate = v); + public static readonly StyledProperty DisplayDateProperty = + AvaloniaProperty.Register(nameof(DisplayDate)); /// /// Defines the property. /// - public static readonly DirectProperty DisplayDateStartProperty = - AvaloniaProperty.RegisterDirect( - nameof(DisplayDateStart), - o => o.DisplayDateStart, - (o, v) => o.DisplayDateStart = v); + public static readonly StyledProperty DisplayDateStartProperty = + AvaloniaProperty.Register( + nameof(DisplayDateStart)); /// /// Defines the property. /// - public static readonly DirectProperty DisplayDateEndProperty = - AvaloniaProperty.RegisterDirect( - nameof(DisplayDateEnd), - o => o.DisplayDateEnd, - (o, v) => o.DisplayDateEnd = v); + public static readonly StyledProperty DisplayDateEndProperty = + AvaloniaProperty.Register( + nameof(DisplayDateEnd)); /// /// Defines the property. @@ -44,11 +37,9 @@ public partial class CalendarDatePicker /// /// Defines the property. /// - public static readonly DirectProperty IsDropDownOpenProperty = - AvaloniaProperty.RegisterDirect( - nameof(IsDropDownOpen), - o => o.IsDropDownOpen, - (o, v) => o.IsDropDownOpen = v); + public static readonly StyledProperty IsDropDownOpenProperty = + AvaloniaProperty.Register( + nameof(IsDropDownOpen)); /// /// Defines the property. @@ -59,11 +50,9 @@ public partial class CalendarDatePicker /// /// Defines the property. /// - public static readonly DirectProperty SelectedDateProperty = - AvaloniaProperty.RegisterDirect( + public static readonly StyledProperty SelectedDateProperty = + AvaloniaProperty.Register( nameof(SelectedDate), - o => o.SelectedDate, - (o, v) => o.SelectedDate = v, enableDataValidation: true, defaultBindingMode:BindingMode.TwoWay); @@ -88,11 +77,8 @@ public partial class CalendarDatePicker /// /// Defines the property. /// - public static readonly DirectProperty TextProperty = - AvaloniaProperty.RegisterDirect( - nameof(Text), - o => o.Text, - (o, v) => o.Text = v); + public static readonly StyledProperty TextProperty = + AvaloniaProperty.Register(nameof(Text)); /// /// Defines the property. @@ -141,8 +127,8 @@ public partial class CalendarDatePicker /// public DateTime DisplayDate { - get => _displayDate; - set => SetAndRaise(DisplayDateProperty, ref _displayDate, value); + get => GetValue(DisplayDateProperty); + set => SetValue(DisplayDateProperty, value); } /// @@ -151,8 +137,8 @@ public DateTime DisplayDate /// The first date to display. public DateTime? DisplayDateStart { - get => _displayDateStart; - set => SetAndRaise(DisplayDateStartProperty, ref _displayDateStart, value); + get => GetValue(DisplayDateStartProperty); + set => SetValue(DisplayDateStartProperty, value); } /// @@ -161,8 +147,8 @@ public DateTime? DisplayDateStart /// The last date to display. public DateTime? DisplayDateEnd { - get => _displayDateEnd; - set => SetAndRaise(DisplayDateEndProperty, ref _displayDateEnd, value); + get => GetValue(DisplayDateEndProperty); + set => SetValue(DisplayDateEndProperty, value); } /// @@ -188,8 +174,8 @@ public DayOfWeek FirstDayOfWeek /// public bool IsDropDownOpen { - get => _isDropDownOpen; - set => SetAndRaise(IsDropDownOpenProperty, ref _isDropDownOpen, value); + get => GetValue(IsDropDownOpenProperty); + set => SetValue(IsDropDownOpenProperty, value); } /// @@ -223,8 +209,8 @@ public bool IsTodayHighlighted /// public DateTime? SelectedDate { - get => _selectedDate; - set => SetAndRaise(SelectedDateProperty, ref _selectedDate, value); + get => GetValue(SelectedDateProperty); + set => SetValue(SelectedDateProperty, value); } /// @@ -264,8 +250,8 @@ public string CustomDateFormatString /// public string? Text { - get => _text; - set => SetAndRaise(TextProperty, ref _text, value); + get => GetValue(TextProperty); + set => SetValue(TextProperty, value); } /// diff --git a/src/Avalonia.Controls/CalendarDatePicker/CalendarDatePicker.cs b/src/Avalonia.Controls/CalendarDatePicker/CalendarDatePicker.cs index 869bdeabea8..c091d076328 100644 --- a/src/Avalonia.Controls/CalendarDatePicker/CalendarDatePicker.cs +++ b/src/Avalonia.Controls/CalendarDatePicker/CalendarDatePicker.cs @@ -45,12 +45,6 @@ public partial class CalendarDatePicker : TemplatedControl private DateTime? _onOpenSelectedDate; private bool _settingSelectedDate; - private DateTime _displayDate; - private DateTime? _displayDateStart; - private DateTime? _displayDateEnd; - private bool _isDropDownOpen; - private DateTime? _selectedDate; - private string? _text; private bool _suspendTextChangeHandler; private bool _isPopupClosing; private bool _ignoreButtonClick; @@ -92,9 +86,9 @@ static CalendarDatePicker() /// public CalendarDatePicker() { - FirstDayOfWeek = DateTimeHelper.GetCurrentDateFormat().FirstDayOfWeek; + SetCurrentValue(FirstDayOfWeekProperty, DateTimeHelper.GetCurrentDateFormat().FirstDayOfWeek); _defaultText = string.Empty; - DisplayDate = DateTime.Today; + SetCurrentValue(DisplayDateProperty, DateTime.Today); } /// @@ -257,7 +251,7 @@ protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs chang Threading.Dispatcher.UIThread.InvokeAsync(() => { _settingSelectedDate = true; - Text = DateTimeToString(day); + SetCurrentValue(TextProperty, DateTimeToString(day)); _settingSelectedDate = false; OnDateSelected(addedDate, removedDate); }); @@ -268,7 +262,7 @@ protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs chang // be changed by the Calendar if ((day.Month != DisplayDate.Month || day.Year != DisplayDate.Year) && (_calendar == null || !_calendar.CalendarDatePickerDisplayDateFlag)) { - DisplayDate = day; + SetCurrentValue(DisplayDateProperty, day); } if(_calendar != null) @@ -317,7 +311,7 @@ protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs chang if (!_settingSelectedDate) { _settingSelectedDate = true; - SelectedDate = null; + SetCurrentValue(SelectedDateProperty, null); _settingSelectedDate = false; } } @@ -400,7 +394,7 @@ protected override void OnPointerWheelChanged(PointerWheelEventArgs e) DateTime? newDate = DateTimeHelper.AddDays(selectedDate, e.Delta.Y > 0 ? -1 : 1); if (newDate.HasValue && Calendar.IsValidDateSelection(_calendar, newDate.Value)) { - SelectedDate = newDate; + SetCurrentValue(SelectedDateProperty, newDate); e.Handled = true; } } @@ -478,7 +472,7 @@ private void OnDateFormatChanged() { if (SelectedDate.HasValue) { - Text = DateTimeToString(SelectedDate.Value); + SetCurrentValue(TextProperty, DateTimeToString(SelectedDate.Value)); } else if (string.IsNullOrEmpty(_textBox.Text)) { @@ -491,7 +485,7 @@ private void OnDateFormatChanged() if (date != null) { string? s = DateTimeToString((DateTime)date); - Text = s; + SetCurrentValue(TextProperty, s); } } } @@ -547,7 +541,7 @@ private void OnCalendarOpened(EventArgs e) private void Calendar_DayButtonMouseUp(object? sender, PointerReleasedEventArgs e) { Focus(); - IsDropDownOpen = false; + SetCurrentValue(IsDropDownOpenProperty, false); } private void Calendar_DisplayDateChanged(object? sender, CalendarDateChangedEventArgs e) @@ -564,13 +558,13 @@ private void Calendar_SelectedDatesChanged(object? sender, SelectionChangedEvent if (e.AddedItems.Count > 0 && SelectedDate.HasValue && DateTime.Compare((DateTime)e.AddedItems[0]!, SelectedDate.Value) != 0) { - SelectedDate = (DateTime?)e.AddedItems[0]; + SetCurrentValue(SelectedDateProperty, (DateTime?)e.AddedItems[0]); } else { if (e.AddedItems.Count == 0) { - SelectedDate = null; + SetCurrentValue(SelectedDateProperty, null); return; } @@ -578,7 +572,7 @@ private void Calendar_SelectedDatesChanged(object? sender, SelectionChangedEvent { if (e.AddedItems.Count > 0) { - SelectedDate = (DateTime?)e.AddedItems[0]; + SetCurrentValue(SelectedDateProperty, (DateTime?)e.AddedItems[0]); } } } @@ -600,18 +594,18 @@ private void Calendar_KeyDown(object? sender, KeyEventArgs e) && (e.Key == Key.Enter || e.Key == Key.Space || e.Key == Key.Escape)) { Focus(); - IsDropDownOpen = false; + SetCurrentValue(IsDropDownOpenProperty, false); if (e.Key == Key.Escape) { - SelectedDate = _onOpenSelectedDate; + SetCurrentValue(SelectedDateProperty, _onOpenSelectedDate); } } } private void TextBox_GotFocus(object? sender, RoutedEventArgs e) { - IsDropDownOpen = false; + SetCurrentValue(IsDropDownOpenProperty, false); } private void TextBox_KeyDown(object? sender, KeyEventArgs e) @@ -627,7 +621,7 @@ private void TextBox_TextChanged() if (_textBox != null) { _suspendTextChangeHandler = true; - Text = _textBox.Text; + SetCurrentValue(TextProperty, _textBox.Text); _suspendTextChangeHandler = false; } } @@ -660,7 +654,7 @@ private void DropDownButton_Click(object? sender, RoutedEventArgs e) private void PopUp_Closed(object? sender, EventArgs e) { - IsDropDownOpen = false; + SetCurrentValue(IsDropDownOpenProperty, false); if(!_isPopupClosing) { @@ -678,12 +672,12 @@ private void TogglePopUp() if (IsDropDownOpen) { Focus(); - IsDropDownOpen = false; + SetCurrentValue(IsDropDownOpenProperty, false); } else { SetSelectedDate(); - IsDropDownOpen = true; + SetCurrentValue(IsDropDownOpenProperty, true); _calendar!.Focus(); } } @@ -821,14 +815,14 @@ private void SetSelectedDate() if (SelectedDate != d) { - SelectedDate = d; + SetCurrentValue(SelectedDateProperty, d); } } else { if (SelectedDate != null) { - SelectedDate = null; + SetCurrentValue(SelectedDateProperty, null); } } } @@ -838,7 +832,7 @@ private void SetSelectedDate() if (SelectedDate != d) { - SelectedDate = d; + SetCurrentValue(SelectedDateProperty, d); } } } @@ -884,7 +878,7 @@ private void SetWaterMarkText() if (string.IsNullOrEmpty(Watermark) && !UseFloatingWatermark) { DateTimeFormatInfo dtfi = DateTimeHelper.GetCurrentDateFormat(); - Text = string.Empty; + SetCurrentValue(TextProperty, string.Empty); _defaultText = string.Empty; var watermarkFormat = "<{0}>"; string watermarkText; diff --git a/src/Avalonia.Controls/ComboBox.cs b/src/Avalonia.Controls/ComboBox.cs index 17a6ad7a09e..f6e4b32d6b3 100644 --- a/src/Avalonia.Controls/ComboBox.cs +++ b/src/Avalonia.Controls/ComboBox.cs @@ -35,11 +35,8 @@ public class ComboBox : SelectingItemsControl /// /// Defines the property. /// - public static readonly DirectProperty IsDropDownOpenProperty = - AvaloniaProperty.RegisterDirect( - nameof(IsDropDownOpen), - o => o.IsDropDownOpen, - (o, v) => o.IsDropDownOpen = v); + public static readonly StyledProperty IsDropDownOpenProperty = + AvaloniaProperty.Register(nameof(IsDropDownOpen)); /// /// Defines the property. @@ -77,7 +74,6 @@ public class ComboBox : SelectingItemsControl public static readonly StyledProperty VerticalContentAlignmentProperty = ContentControl.VerticalContentAlignmentProperty.AddOwner(); - private bool _isDropDownOpen; private Popup? _popup; private object? _selectionBoxItem; private readonly CompositeDisposable _subscriptionsOnOpen = new CompositeDisposable(); @@ -107,8 +103,8 @@ static ComboBox() /// public bool IsDropDownOpen { - get => _isDropDownOpen; - set => SetAndRaise(IsDropDownOpenProperty, ref _isDropDownOpen, value); + get => GetValue(IsDropDownOpenProperty); + set => SetValue(IsDropDownOpenProperty, value); } /// @@ -123,10 +119,10 @@ public double MaxDropDownHeight /// /// Gets or sets the item to display as the control's content. /// - protected object? SelectionBoxItem + public object? SelectionBoxItem { get => _selectionBoxItem; - set => SetAndRaise(SelectionBoxItemProperty, ref _selectionBoxItem, value); + protected set => SetAndRaise(SelectionBoxItemProperty, ref _selectionBoxItem, value); } /// @@ -191,23 +187,23 @@ protected override void OnKeyDown(KeyEventArgs e) if ((e.Key == Key.F4 && e.KeyModifiers.HasAllFlags(KeyModifiers.Alt) == false) || ((e.Key == Key.Down || e.Key == Key.Up) && e.KeyModifiers.HasAllFlags(KeyModifiers.Alt))) { - IsDropDownOpen = !IsDropDownOpen; + SetCurrentValue(IsDropDownOpenProperty, !IsDropDownOpen); e.Handled = true; } else if (IsDropDownOpen && e.Key == Key.Escape) { - IsDropDownOpen = false; + SetCurrentValue(IsDropDownOpenProperty, false); e.Handled = true; } else if (!IsDropDownOpen && (e.Key == Key.Enter || e.Key == Key.Space)) { - IsDropDownOpen = true; + SetCurrentValue(IsDropDownOpenProperty, true); e.Handled = true; } else if (IsDropDownOpen && (e.Key == Key.Enter || e.Key == Key.Space)) { SelectFocusedItem(); - IsDropDownOpen = false; + SetCurrentValue(IsDropDownOpenProperty, false); e.Handled = true; } else if (!IsDropDownOpen) @@ -291,7 +287,7 @@ protected override void OnPointerReleased(PointerReleasedEventArgs e) } else { - IsDropDownOpen = !IsDropDownOpen; + SetCurrentValue(IsDropDownOpenProperty, !IsDropDownOpen); e.Handled = true; } } @@ -390,7 +386,7 @@ private void IsVisibleChanged(bool isVisible) { if (!isVisible && IsDropDownOpen) { - IsDropDownOpen = false; + SetCurrentValue(IsDropDownOpenProperty, false); } } diff --git a/src/Avalonia.Controls/DateTimePickers/DatePicker.cs b/src/Avalonia.Controls/DateTimePickers/DatePicker.cs index bb05cd1b1f1..118183102a0 100644 --- a/src/Avalonia.Controls/DateTimePickers/DatePicker.cs +++ b/src/Avalonia.Controls/DateTimePickers/DatePicker.cs @@ -1,7 +1,6 @@ using Avalonia.Controls.Metadata; using Avalonia.Controls.Primitives; using Avalonia.Controls.Shapes; -using Avalonia.Controls.Templates; using Avalonia.Data; using Avalonia.Interactivity; using Avalonia.Layout; @@ -29,65 +28,56 @@ public class DatePicker : TemplatedControl /// /// Define the Property /// - public static readonly DirectProperty DayFormatProperty = - AvaloniaProperty.RegisterDirect(nameof(DayFormat), - x => x.DayFormat, (x, v) => x.DayFormat = v); + public static readonly StyledProperty DayFormatProperty = + AvaloniaProperty.Register(nameof(DayFormat), "%d"); /// /// Defines the Property /// - public static readonly DirectProperty DayVisibleProperty = - AvaloniaProperty.RegisterDirect(nameof(DayVisible), - x => x.DayVisible, (x, v) => x.DayVisible = v); + public static readonly StyledProperty DayVisibleProperty = + AvaloniaProperty.Register(nameof(DayVisible), true); /// /// Defines the Property /// - public static readonly DirectProperty MaxYearProperty = - AvaloniaProperty.RegisterDirect(nameof(MaxYear), - x => x.MaxYear, (x, v) => x.MaxYear = v); + public static readonly StyledProperty MaxYearProperty = + AvaloniaProperty.Register(nameof(MaxYear), DateTimeOffset.MaxValue, coerce: CoerceMaxYear); /// /// Defines the Property /// - public static readonly DirectProperty MinYearProperty = - AvaloniaProperty.RegisterDirect(nameof(MinYear), - x => x.MinYear, (x, v) => x.MinYear = v); + public static readonly StyledProperty MinYearProperty = + AvaloniaProperty.Register(nameof(MinYear), DateTimeOffset.MinValue, coerce: CoerceMinYear); /// /// Defines the Property /// - public static readonly DirectProperty MonthFormatProperty = - AvaloniaProperty.RegisterDirect(nameof(MonthFormat), - x => x.MonthFormat, (x, v) => x.MonthFormat = v); + public static readonly StyledProperty MonthFormatProperty = + AvaloniaProperty.Register(nameof(MonthFormat), "MMMM"); /// /// Defines the Property /// - public static readonly DirectProperty MonthVisibleProperty = - AvaloniaProperty.RegisterDirect(nameof(MonthVisible), - x => x.MonthVisible, (x, v) => x.MonthVisible = v); + public static readonly StyledProperty MonthVisibleProperty = + AvaloniaProperty.Register(nameof(MonthVisible), true); /// /// Defines the Property /// - public static readonly DirectProperty YearFormatProperty = - AvaloniaProperty.RegisterDirect(nameof(YearFormat), - x => x.YearFormat, (x, v) => x.YearFormat = v); + public static readonly StyledProperty YearFormatProperty = + AvaloniaProperty.Register(nameof(YearFormat), "yyyy"); /// /// Defines the Property /// - public static readonly DirectProperty YearVisibleProperty = - AvaloniaProperty.RegisterDirect(nameof(YearVisible), - x => x.YearVisible, (x, v) => x.YearVisible = v); + public static readonly StyledProperty YearVisibleProperty = + AvaloniaProperty.Register(nameof(YearVisible), true); /// /// Defines the Property /// - public static readonly DirectProperty SelectedDateProperty = - AvaloniaProperty.RegisterDirect(nameof(SelectedDate), - x => x.SelectedDate, (x, v) => x.SelectedDate = v, + public static readonly StyledProperty SelectedDateProperty = + AvaloniaProperty.Register(nameof(SelectedDate), defaultBindingMode: BindingMode.TwoWay); // Template Items @@ -103,28 +93,20 @@ public class DatePicker : TemplatedControl private bool _areControlsAvailable; - private string _dayFormat = "%d"; - private bool _dayVisible = true; - private DateTimeOffset _maxYear; - private DateTimeOffset _minYear; - private string _monthFormat = "MMMM"; - private bool _monthVisible = true; - private string _yearFormat = "yyyy"; - private bool _yearVisible = true; - private DateTimeOffset? _selectedDate; - public DatePicker() { PseudoClasses.Set(":hasnodate", true); var now = DateTimeOffset.Now; - _minYear = new DateTimeOffset(now.Date.Year - 100, 1, 1, 0, 0, 0, now.Offset); - _maxYear = new DateTimeOffset(now.Date.Year + 100, 12, 31, 0, 0, 0, now.Offset); + SetCurrentValue(MinYearProperty, new DateTimeOffset(now.Date.Year - 100, 1, 1, 0, 0, 0, now.Offset)); + SetCurrentValue(MaxYearProperty, new DateTimeOffset(now.Date.Year + 100, 12, 31, 0, 0, 0, now.Offset)); } + private static void OnGridVisibilityChanged(DatePicker sender, AvaloniaPropertyChangedEventArgs e) => sender.SetGrid(); + public string DayFormat { - get => _dayFormat; - set => SetAndRaise(DayFormatProperty, ref _dayFormat, value); + get => GetValue(DayFormatProperty); + set => SetValue(DayFormatProperty, value); } /// @@ -132,12 +114,8 @@ public string DayFormat /// public bool DayVisible { - get => _dayVisible; - set - { - SetAndRaise(DayVisibleProperty, ref _dayVisible, value); - SetGrid(); - } + get => GetValue(DayVisibleProperty); + set => SetValue(DayVisibleProperty, value); } /// @@ -145,16 +123,24 @@ public bool DayVisible /// public DateTimeOffset MaxYear { - get => _maxYear; - set - { - if (value < MinYear) - throw new InvalidOperationException("MaxDate cannot be less than MinDate"); - SetAndRaise(MaxYearProperty, ref _maxYear, value); + get => GetValue(MaxYearProperty); + set => SetValue(MaxYearProperty, value); + } - if (SelectedDate.HasValue && SelectedDate.Value > value) - SelectedDate = value; + private static DateTimeOffset CoerceMaxYear(AvaloniaObject sender, DateTimeOffset value) + { + if (value < sender.GetValue(MinYearProperty)) + { + throw new InvalidOperationException($"{MaxYearProperty.Name} cannot be less than {MinYearProperty.Name}"); } + + return value; + } + + private void OnMaxYearChanged(DateTimeOffset? value) + { + if (SelectedDate.HasValue && SelectedDate.Value > value) + SetCurrentValue(SelectedDateProperty, value); } /// @@ -162,16 +148,24 @@ public DateTimeOffset MaxYear /// public DateTimeOffset MinYear { - get => _minYear; - set - { - if (value > MaxYear) - throw new InvalidOperationException("MinDate cannot be greater than MaxDate"); - SetAndRaise(MinYearProperty, ref _minYear, value); + get => GetValue(MinYearProperty); + set => SetValue(MinYearProperty, value); + } - if (SelectedDate.HasValue && SelectedDate.Value < value) - SelectedDate = value; + private static DateTimeOffset CoerceMinYear(AvaloniaObject sender, DateTimeOffset value) + { + if (value > sender.GetValue(MaxYearProperty)) + { + throw new InvalidOperationException($"{MinYearProperty.Name} cannot be greater than {MaxYearProperty.Name}"); } + + return value; + } + + private void OnMinYearChanged(DateTimeOffset? value) + { + if (SelectedDate.HasValue && SelectedDate.Value < value) + SetCurrentValue(SelectedDateProperty, value); } /// @@ -179,8 +173,8 @@ public DateTimeOffset MinYear /// public string MonthFormat { - get => _monthFormat; - set => SetAndRaise(MonthFormatProperty, ref _monthFormat, value); + get => GetValue(MonthFormatProperty); + set => SetValue(MonthFormatProperty, value); } /// @@ -188,12 +182,8 @@ public string MonthFormat /// public bool MonthVisible { - get => _monthVisible; - set - { - SetAndRaise(MonthVisibleProperty, ref _monthVisible, value); - SetGrid(); - } + get => GetValue(MonthVisibleProperty); + set => SetValue(MonthVisibleProperty, value); } /// @@ -201,8 +191,8 @@ public bool MonthVisible /// public string YearFormat { - get => _yearFormat; - set => SetAndRaise(YearFormatProperty, ref _yearFormat, value); + get => GetValue(YearFormatProperty); + set => SetValue(YearFormatProperty, value); } /// @@ -210,12 +200,8 @@ public string YearFormat /// public bool YearVisible { - get => _yearVisible; - set - { - SetAndRaise(YearVisibleProperty, ref _yearVisible, value); - SetGrid(); - } + get => GetValue(YearVisibleProperty); + set => SetValue(YearVisibleProperty, value); } /// @@ -223,14 +209,8 @@ public bool YearVisible /// public DateTimeOffset? SelectedDate { - get => _selectedDate; - set - { - var old = _selectedDate; - SetAndRaise(SelectedDateProperty, ref _selectedDate, value); - SetSelectedDateText(); - OnSelectedDateChanged(this, new DatePickerSelectedValueChangedEventArgs(old, value)); - } + get => GetValue(SelectedDateProperty); + set => SetValue(SelectedDateProperty, value); } /// @@ -287,6 +267,31 @@ protected override void OnApplyTemplate(TemplateAppliedEventArgs e) } } + protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) + { + base.OnPropertyChanged(change); + + if (change.Property == DayVisibleProperty || change.Property == MonthVisibleProperty || change.Property == YearVisibleProperty) + { + SetGrid(); + } + else if (change.Property == MaxYearProperty) + { + OnMaxYearChanged(change.GetNewValue()); + } + else if (change.Property == MinYearProperty) + { + OnMinYearChanged(change.GetNewValue()); + } + else if (change.Property == SelectedDateProperty) + { + SetSelectedDateText(); + + var (oldValue, newValue) = change.GetOldAndNewValue(); + OnSelectedDateChanged(this, new DatePickerSelectedValueChangedEventArgs(oldValue, newValue)); + } + } + private void OnDismissPicker(object? sender, EventArgs e) { _popup!.Close(); @@ -296,7 +301,7 @@ private void OnDismissPicker(object? sender, EventArgs e) private void OnConfirmed(object? sender, EventArgs e) { _popup!.Close(); - SelectedDate = _presenter!.Date; + SetCurrentValue(SelectedDateProperty, _presenter!.Date); } private void SetGrid() diff --git a/src/Avalonia.Controls/DateTimePickers/DatePickerPresenter.cs b/src/Avalonia.Controls/DateTimePickers/DatePickerPresenter.cs index 2057480490f..0ae743f30a1 100644 --- a/src/Avalonia.Controls/DateTimePickers/DatePickerPresenter.cs +++ b/src/Avalonia.Controls/DateTimePickers/DatePickerPresenter.cs @@ -35,65 +35,72 @@ public class DatePickerPresenter : PickerPresenterBase /// /// Defines the Property /// - public static readonly DirectProperty DateProperty = - AvaloniaProperty.RegisterDirect(nameof(Date), - x => x.Date, (x, v) => x.Date = v); + public static readonly StyledProperty DateProperty = + AvaloniaProperty.Register(nameof(Date), coerce: CoerceDate); + + private static DateTimeOffset CoerceDate(AvaloniaObject sender, DateTimeOffset value) + { + var max = sender.GetValue(MaxYearProperty); + if (value > max) + { + return max; + } + var min = sender.GetValue(MinYearProperty); + if (value < min) + { + return min; + } + + return value; + } /// /// Defines the Property /// - public static readonly DirectProperty DayFormatProperty = - DatePicker.DayFormatProperty.AddOwner(x => - x.DayFormat, (x, v) => x.DayFormat = v); + public static readonly StyledProperty DayFormatProperty = + DatePicker.DayFormatProperty.AddOwner(); /// /// Defines the Property /// - public static readonly DirectProperty DayVisibleProperty = - DatePicker.DayVisibleProperty.AddOwner(x => - x.DayVisible, (x, v) => x.DayVisible = v); + public static readonly StyledProperty DayVisibleProperty = + DatePicker.DayVisibleProperty.AddOwner(); /// /// Defines the Property /// - public static readonly DirectProperty MaxYearProperty = - DatePicker.MaxYearProperty.AddOwner(x => - x.MaxYear, (x, v) => x.MaxYear = v); + public static readonly StyledProperty MaxYearProperty = + DatePicker.MaxYearProperty.AddOwner(); /// /// Defines the Property /// - public static readonly DirectProperty MinYearProperty = - DatePicker.MinYearProperty.AddOwner(x => - x.MinYear, (x, v) => x.MinYear = v); + public static readonly StyledProperty MinYearProperty = + DatePicker.MinYearProperty.AddOwner(); /// /// Defines the Property /// - public static readonly DirectProperty MonthFormatProperty = - DatePicker.MonthFormatProperty.AddOwner(x => - x.MonthFormat, (x, v) => x.MonthFormat = v); + public static readonly StyledProperty MonthFormatProperty = + DatePicker.MonthFormatProperty.AddOwner(); /// /// Defines the Property /// - public static readonly DirectProperty MonthVisibleProperty = - DatePicker.MonthVisibleProperty.AddOwner(x => - x.MonthVisible, (x, v) => x.MonthVisible = v); + public static readonly StyledProperty MonthVisibleProperty = + DatePicker.MonthVisibleProperty.AddOwner(); /// /// Defines the Property /// - public static readonly DirectProperty YearFormatProperty = - DatePicker.YearFormatProperty.AddOwner(x => - x.YearFormat, (x, v) => x.YearFormat = v); + public static readonly StyledProperty YearFormatProperty = + DatePicker.YearFormatProperty.AddOwner(); /// /// Defines the Property /// - public static readonly DirectProperty YearVisibleProperty = - DatePicker.YearVisibleProperty.AddOwner(x => - x.YearVisible, (x, v) => x.YearVisible = v); + public static readonly StyledProperty YearVisibleProperty = + DatePicker.YearVisibleProperty.AddOwner(); // Template Items private Grid? _pickerContainer; @@ -114,15 +121,6 @@ public class DatePickerPresenter : PickerPresenterBase private Button? _dayDownButton; private Button? _yearDownButton; - private DateTimeOffset _date; - private string _dayFormat = "%d"; - private bool _dayVisible = true; - private DateTimeOffset _maxYear; - private DateTimeOffset _minYear; - private string _monthFormat = "MMMM"; - private bool _monthVisible = true; - private string _yearFormat = "yyyy"; - private bool _yearVisible = true; private DateTimeOffset _syncDate; private readonly GregorianCalendar _calendar; @@ -131,11 +129,20 @@ public class DatePickerPresenter : PickerPresenterBase public DatePickerPresenter() { var now = DateTimeOffset.Now; - _minYear = new DateTimeOffset(now.Year - 100, 1, 1, 0, 0, 0, now.Offset); - _maxYear = new DateTimeOffset(now.Year + 100, 12, 31, 0, 0, 0, now.Offset); - _date = now; + SetCurrentValue(MinYearProperty, new DateTimeOffset(now.Year - 100, 1, 1, 0, 0, 0, now.Offset)); + SetCurrentValue(MaxYearProperty, new DateTimeOffset(now.Year + 100, 12, 31, 0, 0, 0, now.Offset)); + SetCurrentValue(DateProperty, now); _calendar = new GregorianCalendar(); - KeyboardNavigation.SetTabNavigation(this, KeyboardNavigationMode.Cycle); + } + + static DatePickerPresenter() + { + KeyboardNavigation.TabNavigationProperty.OverrideDefaultValue(KeyboardNavigationMode.Cycle); + } + + private static void OnDateRangeChanged(DatePickerPresenter sender, AvaloniaPropertyChangedEventArgs e) + { + sender.CoerceValue(DateProperty); } /// @@ -143,13 +150,14 @@ public DatePickerPresenter() /// public DateTimeOffset Date { - get => _date; - set - { - SetAndRaise(DateProperty, ref _date, value); - _syncDate = Date; - InitPicker(); - } + get => GetValue(DateProperty); + set => SetValue(DateProperty, value); + } + + private void OnDateChanged(DateTimeOffset newValue) + { + _syncDate = newValue; + InitPicker(); } /// @@ -157,8 +165,8 @@ public DateTimeOffset Date /// public string DayFormat { - get => _dayFormat; - set => SetAndRaise(DayFormatProperty, ref _dayFormat, value); + get => GetValue(DayFormatProperty); + set => SetValue(DayFormatProperty, value); } /// @@ -166,11 +174,8 @@ public string DayFormat /// public bool DayVisible { - get => _dayVisible; - set - { - SetAndRaise(DayVisibleProperty, ref _dayVisible, value); - } + get => GetValue(DayVisibleProperty); + set => SetValue(DayVisibleProperty, value); } /// @@ -178,16 +183,8 @@ public bool DayVisible /// public DateTimeOffset MaxYear { - get => _maxYear; - set - { - if (value < MinYear) - throw new InvalidOperationException("MaxDate cannot be less than MinDate"); - SetAndRaise(MaxYearProperty, ref _maxYear, value); - - if (Date > value) - Date = value; - } + get => GetValue(MaxYearProperty); + set => SetValue(MaxYearProperty, value); } /// @@ -195,16 +192,8 @@ public DateTimeOffset MaxYear /// public DateTimeOffset MinYear { - get => _minYear; - set - { - if (value > MaxYear) - throw new InvalidOperationException("MinDate cannot be greater than MaxDate"); - SetAndRaise(MinYearProperty, ref _minYear, value); - - if (Date < value) - Date = value; - } + get => GetValue(MinYearProperty); + set => SetValue(MinYearProperty, value); } /// @@ -212,8 +201,8 @@ public DateTimeOffset MinYear /// public string MonthFormat { - get => _monthFormat; - set => SetAndRaise(MonthFormatProperty, ref _monthFormat, value); + get => GetValue(MonthFormatProperty); + set => SetValue(MonthFormatProperty, value); } /// @@ -221,11 +210,8 @@ public string MonthFormat /// public bool MonthVisible { - get => _monthVisible; - set - { - SetAndRaise(MonthVisibleProperty, ref _monthVisible, value); - } + get => GetValue(MonthVisibleProperty); + set => SetValue(MonthVisibleProperty, value); } /// @@ -233,8 +219,8 @@ public bool MonthVisible /// public string YearFormat { - get => _yearFormat; - set => SetAndRaise(YearFormatProperty, ref _yearFormat, value); + get => GetValue(YearFormatProperty); + set => SetValue(YearFormatProperty, value); } /// @@ -242,11 +228,8 @@ public string YearFormat /// public bool YearVisible { - get => _yearVisible; - set - { - SetAndRaise(YearVisibleProperty, ref _yearVisible, value); - } + get => GetValue(YearVisibleProperty); + set => SetValue(YearVisibleProperty, value); } protected override void OnApplyTemplate(TemplateAppliedEventArgs e) @@ -317,6 +300,20 @@ protected override void OnApplyTemplate(TemplateAppliedEventArgs e) InitPicker(); } + protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) + { + base.OnPropertyChanged(change); + + if (change.Property == DateProperty) + { + OnDateChanged(change.GetNewValue()); + } + else if (change.Property == MaxYearProperty || change.Property == MinYearProperty) + { + OnDateRangeChanged(this, change); + } + } + protected override void OnKeyDown(KeyEventArgs e) { switch (e.Key) @@ -334,7 +331,7 @@ protected override void OnKeyDown(KeyEventArgs e) } break; case Key.Enter: - Date = _syncDate; + SetCurrentValue(DateProperty, _syncDate); OnConfirmed(); e.Handled = true; break; @@ -381,13 +378,13 @@ private void InitPicker() _monthSelector.SelectedValue = dt.Month; _monthSelector.FormatDate = dt.Date; } - + if (YearVisible) { _yearSelector.SelectedValue = dt.Year; _yearSelector.FormatDate = dt.Date; } - + _suppressUpdateSelection = false; SetInitialFocus(); @@ -471,7 +468,7 @@ private void OnDismissButtonClicked(object? sender, RoutedEventArgs e) private void OnAcceptButtonClicked(object? sender, RoutedEventArgs e) { - Date = _syncDate; + SetCurrentValue(DateProperty, _syncDate); OnConfirmed(); } diff --git a/src/Avalonia.Controls/DateTimePickers/TimePicker.cs b/src/Avalonia.Controls/DateTimePickers/TimePicker.cs index a7a6881fe50..2f49a44b8cd 100644 --- a/src/Avalonia.Controls/DateTimePickers/TimePicker.cs +++ b/src/Avalonia.Controls/DateTimePickers/TimePicker.cs @@ -1,7 +1,6 @@ using Avalonia.Controls.Metadata; using Avalonia.Controls.Primitives; using Avalonia.Controls.Shapes; -using Avalonia.Controls.Templates; using Avalonia.Data; using Avalonia.Layout; using System; @@ -30,23 +29,20 @@ public class TimePicker : TemplatedControl /// /// Defines the property /// - public static readonly DirectProperty MinuteIncrementProperty = - AvaloniaProperty.RegisterDirect(nameof(MinuteIncrement), - x => x.MinuteIncrement, (x, v) => x.MinuteIncrement = v); + public static readonly StyledProperty MinuteIncrementProperty = + AvaloniaProperty.Register(nameof(MinuteIncrement), 1, coerce: CoerceMinuteIncrement); /// /// Defines the property /// - public static readonly DirectProperty ClockIdentifierProperty = - AvaloniaProperty.RegisterDirect(nameof(ClockIdentifier), - x => x.ClockIdentifier, (x, v) => x.ClockIdentifier = v); + public static readonly StyledProperty ClockIdentifierProperty = + AvaloniaProperty.Register(nameof(ClockIdentifier), "12HourClock", coerce: CoerceClockIdentifier); /// /// Defines the property /// - public static readonly DirectProperty SelectedTimeProperty = - AvaloniaProperty.RegisterDirect(nameof(SelectedTime), - x => x.SelectedTime, (x, v) => x.SelectedTime = v, + public static readonly StyledProperty SelectedTimeProperty = + AvaloniaProperty.Register(nameof(SelectedTime), defaultBindingMode: BindingMode.TwoWay); // Template Items @@ -63,17 +59,13 @@ public class TimePicker : TemplatedControl private Grid? _contentGrid; private Popup? _popup; - private TimeSpan? _selectedTime; - private int _minuteIncrement = 1; - private string _clockIdentifier = "12HourClock"; - public TimePicker() { PseudoClasses.Set(":hasnotime", true); var timePattern = CultureInfo.CurrentCulture.DateTimeFormat.ShortTimePattern; if (timePattern.IndexOf("H") != -1) - _clockIdentifier = "24HourClock"; + SetCurrentValue(ClockIdentifierProperty, "24HourClock"); } /// @@ -81,14 +73,16 @@ public TimePicker() /// public int MinuteIncrement { - get => _minuteIncrement; - set - { - if (value < 1 || value > 59) - throw new ArgumentOutOfRangeException("1 >= MinuteIncrement <= 59"); - SetAndRaise(MinuteIncrementProperty, ref _minuteIncrement, value); - SetSelectedTimeText(); - } + get => GetValue(MinuteIncrementProperty); + set => SetValue(MinuteIncrementProperty, value); + } + + private static int CoerceMinuteIncrement(AvaloniaObject sender, int value) + { + if (value < 1 || value > 59) + throw new ArgumentOutOfRangeException(null, "1 >= MinuteIncrement <= 59"); + + return value; } /// @@ -96,15 +90,17 @@ public int MinuteIncrement /// public string ClockIdentifier { - get => _clockIdentifier; - set - { - if (!(string.IsNullOrEmpty(value) || value == "12HourClock" || value == "24HourClock")) - throw new ArgumentException("Invalid ClockIdentifier"); - SetAndRaise(ClockIdentifierProperty, ref _clockIdentifier, value); - SetGrid(); - SetSelectedTimeText(); - } + + get => GetValue(ClockIdentifierProperty); + set => SetValue(ClockIdentifierProperty, value); + } + + private static string CoerceClockIdentifier(AvaloniaObject sender, string value) + { + if (!(string.IsNullOrEmpty(value) || value == "12HourClock" || value == "24HourClock")) + throw new ArgumentException("Invalid ClockIdentifier", default(string)); + + return value; } /// @@ -112,14 +108,8 @@ public string ClockIdentifier /// public TimeSpan? SelectedTime { - get => _selectedTime; - set - { - var old = _selectedTime; - SetAndRaise(SelectedTimeProperty, ref _selectedTime, value); - OnSelectedTimeChanged(old, value); - SetSelectedTimeText(); - } + get => GetValue(SelectedTimeProperty); + set => SetValue(SelectedTimeProperty, value); } /// @@ -173,6 +163,27 @@ protected override void OnApplyTemplate(TemplateAppliedEventArgs e) } } + protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) + { + base.OnPropertyChanged(change); + + if (change.Property == MinuteIncrementProperty) + { + SetSelectedTimeText(); + } + else if (change.Property == ClockIdentifierProperty) + { + SetGrid(); + SetSelectedTimeText(); + } + else if (change.Property == SelectedTimeProperty) + { + var (oldValue, newValue) = change.GetOldAndNewValue(); + OnSelectedTimeChanged(oldValue, newValue); + SetSelectedTimeText(); + } + } + private void SetGrid() { if (_contentGrid == null) @@ -270,7 +281,7 @@ private void OnDismissPicker(object? sender, EventArgs e) private void OnConfirmed(object? sender, EventArgs e) { _popup!.Close(); - SelectedTime = _presenter!.Time; + SetCurrentValue(SelectedTimeProperty, _presenter!.Time); } } } diff --git a/src/Avalonia.Controls/DateTimePickers/TimePickerPresenter.cs b/src/Avalonia.Controls/DateTimePickers/TimePickerPresenter.cs index d6599c9f18e..ba06e1b5e65 100644 --- a/src/Avalonia.Controls/DateTimePickers/TimePickerPresenter.cs +++ b/src/Avalonia.Controls/DateTimePickers/TimePickerPresenter.cs @@ -30,28 +30,29 @@ public class TimePickerPresenter : PickerPresenterBase /// /// Defines the property /// - public static readonly DirectProperty MinuteIncrementProperty = - TimePicker.MinuteIncrementProperty.AddOwner(x => x.MinuteIncrement, - (x, v) => x.MinuteIncrement = v); + public static readonly StyledProperty MinuteIncrementProperty = + TimePicker.MinuteIncrementProperty.AddOwner(); /// /// Defines the property /// - public static readonly DirectProperty ClockIdentifierProperty = - TimePicker.ClockIdentifierProperty.AddOwner(x => x.ClockIdentifier, - (x, v) => x.ClockIdentifier = v); + public static readonly StyledProperty ClockIdentifierProperty = + TimePicker.ClockIdentifierProperty.AddOwner(); /// /// Defines the property /// - public static readonly DirectProperty TimeProperty = - AvaloniaProperty.RegisterDirect(nameof(Time), - x => x.Time, (x, v) => x.Time = v); + public static readonly StyledProperty TimeProperty = + AvaloniaProperty.Register(nameof(Time)); public TimePickerPresenter() { - Time = DateTime.Now.TimeOfDay; - KeyboardNavigation.SetTabNavigation(this, KeyboardNavigationMode.Cycle); + SetCurrentValue(TimeProperty, DateTime.Now.TimeOfDay); + } + + static TimePickerPresenter() + { + KeyboardNavigation.TabNavigationProperty.OverrideDefaultValue(KeyboardNavigationMode.Cycle); } // TemplateItems @@ -70,24 +71,13 @@ public TimePickerPresenter() private Button? _minuteDownButton; private Button? _periodDownButton; - // Backing Fields - private TimeSpan _time; - private int _minuteIncrement = 1; - private string _clockIdentifier = "12HourClock"; - /// /// Gets or sets the minute increment in the selector /// public int MinuteIncrement { - get => _minuteIncrement; - set - { - if (value < 1 || value > 59) - throw new ArgumentOutOfRangeException("1 >= MinuteIncrement <= 59"); - SetAndRaise(MinuteIncrementProperty, ref _minuteIncrement, value); - InitPicker(); - } + get => GetValue(MinuteIncrementProperty); + set => SetValue(MinuteIncrementProperty, value); } /// @@ -95,14 +85,8 @@ public int MinuteIncrement /// public string ClockIdentifier { - get => _clockIdentifier; - set - { - if (string.IsNullOrEmpty(value) || !(value == "12HourClock" || value == "24HourClock")) - throw new ArgumentException("Invalid ClockIdentifier"); - SetAndRaise(ClockIdentifierProperty, ref _clockIdentifier, value); - InitPicker(); - } + get => GetValue(ClockIdentifierProperty); + set => SetValue(ClockIdentifierProperty, value); } /// @@ -110,12 +94,8 @@ public string ClockIdentifier /// public TimeSpan Time { - get => _time; - set - { - SetAndRaise(TimeProperty, ref _time, value); - InitPicker(); - } + get => GetValue(TimeProperty); + set => SetValue(TimeProperty, value); } protected override void OnApplyTemplate(TemplateAppliedEventArgs e) @@ -162,6 +142,16 @@ protected override void OnApplyTemplate(TemplateAppliedEventArgs e) InitPicker(); } + protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) + { + base.OnPropertyChanged(change); + + if (change.Property == MinuteIncrementProperty || change.Property == ClockIdentifierProperty || change.Property == TimeProperty) + { + InitPicker(); + } + } + protected override void OnKeyDown(KeyEventArgs e) { switch (e.Key) @@ -197,7 +187,7 @@ protected override void OnConfirmed() hr = per == 1 ? (hr == 12) ? 12 : hr + 12 : per == 0 && hr == 12 ? 0 : hr; } - Time = new TimeSpan(hr, min, 0); + SetCurrentValue(TimeProperty, new TimeSpan(hr, min, 0)); base.OnConfirmed(); } diff --git a/src/Avalonia.Controls/Documents/InlineCollection.cs b/src/Avalonia.Controls/Documents/InlineCollection.cs index 12a096b105a..fe9f5e64a8e 100644 --- a/src/Avalonia.Controls/Documents/InlineCollection.cs +++ b/src/Avalonia.Controls/Documents/InlineCollection.cs @@ -24,7 +24,7 @@ public InlineCollection() this.ForEachItem( x => - { + { x.InlineHost = InlineHost; LogicalChildren?.Add(x); Invalidate(); @@ -92,10 +92,10 @@ public string? Text public override void Add(Inline inline) { if (InlineHost is TextBlock textBlock && !string.IsNullOrEmpty(textBlock._text)) - { + { base.Add(new Run(textBlock._text)); - textBlock._text = null; + textBlock._text = null; } base.Add(inline); @@ -159,7 +159,7 @@ private void OnParentChanged(IAvaloniaList? oldParent, IAvaloniaList /// Defines the property /// - public static readonly DirectProperty ShowModeProperty = - AvaloniaProperty.RegisterDirect(nameof(ShowMode), - x => x.ShowMode, (x, v) => x.ShowMode = v); + public static readonly StyledProperty ShowModeProperty = + AvaloniaProperty.Register(nameof(ShowMode)); /// /// Defines the property /// - public static readonly DirectProperty OverlayInputPassThroughElementProperty = - Popup.OverlayInputPassThroughElementProperty.AddOwner( - o => o._overlayInputPassThroughElement, - (o, v) => o._overlayInputPassThroughElement = v); + public static readonly StyledProperty OverlayInputPassThroughElementProperty = + Popup.OverlayInputPassThroughElementProperty.AddOwner(); /// /// Defines the AttachedFlyout property @@ -56,12 +53,10 @@ public abstract class FlyoutBase : AvaloniaObject, IPopupHostProvider private readonly Lazy _popupLazy; private bool _isOpen; private Control? _target; - private FlyoutShowMode _showMode = FlyoutShowMode.Standard; private Rect? _enlargedPopupRect; private PixelRect? _enlargePopupRectScreenPixelRect; private IDisposable? _transientDisposable; private Action? _popupHostChangedHandler; - private IInputElement? _overlayInputPassThroughElement; static FlyoutBase() { @@ -98,8 +93,8 @@ public FlyoutPlacementMode Placement /// public FlyoutShowMode ShowMode { - get => _showMode; - set => SetAndRaise(ShowModeProperty, ref _showMode, value); + get => GetValue(ShowModeProperty); + set => SetValue(ShowModeProperty, value); } /// @@ -117,8 +112,8 @@ public Control? Target /// public IInputElement? OverlayInputPassThroughElement { - get => _overlayInputPassThroughElement; - set => SetAndRaise(OverlayInputPassThroughElementProperty, ref _overlayInputPassThroughElement, value); + get => GetValue(OverlayInputPassThroughElementProperty); + set => SetValue(OverlayInputPassThroughElementProperty, value); } IPopupHost? IPopupHostProvider.PopupHost => Popup?.Host; @@ -244,7 +239,7 @@ protected virtual bool ShowAtCore(Control placementTarget, bool showAtPointer = { Popup.PlacementTarget = Target = placementTarget; ((ISetLogicalParent)Popup).SetParent(placementTarget); - Popup.SetValue(StyledElement.TemplatedParentProperty, placementTarget.TemplatedParent); + Popup.TemplatedParent = placementTarget.TemplatedParent; } if (Popup.Child == null) diff --git a/src/Avalonia.Controls/Label.cs b/src/Avalonia.Controls/Label.cs index 5c8a6e0a5b0..487d816204b 100644 --- a/src/Avalonia.Controls/Label.cs +++ b/src/Avalonia.Controls/Label.cs @@ -1,11 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Runtime.CompilerServices; -using System.Text; -using Avalonia.Controls.Primitives; -using Avalonia.Controls.Templates; -using Avalonia.Data; -using Avalonia.Input; +using Avalonia.Input; using Avalonia.Interactivity; namespace Avalonia.Controls @@ -18,13 +11,8 @@ public class Label : ContentControl /// /// Defines the Direct property /// - public static readonly DirectProperty TargetProperty = - AvaloniaProperty.RegisterDirect(nameof(Target), lbl => lbl.Target, (lbl, inp) => lbl.Target = inp); - - /// - /// Label focus target storage field - /// - private IInputElement? _target; + public static readonly StyledProperty TargetProperty = + AvaloniaProperty.Register(nameof(Target)); /// /// Label focus Target @@ -32,8 +20,8 @@ public class Label : ContentControl [ResolveByName] public IInputElement? Target { - get => _target; - set => SetAndRaise(TargetProperty, ref _target, value); + get => GetValue(TargetProperty); + set => SetValue(TargetProperty, value); } static Label() diff --git a/src/Avalonia.Controls/MenuItem.cs b/src/Avalonia.Controls/MenuItem.cs index 1670e496b41..03e3444d716 100644 --- a/src/Avalonia.Controls/MenuItem.cs +++ b/src/Avalonia.Controls/MenuItem.cs @@ -27,11 +27,8 @@ public class MenuItem : HeaderedSelectingItemsControl, IMenuItem, ISelectable, I /// /// Defines the property. /// - public static readonly DirectProperty CommandProperty = - Button.CommandProperty.AddOwner( - menuItem => menuItem.Command, - (menuItem, command) => menuItem.Command = command, - enableDataValidation: true); + public static readonly StyledProperty CommandProperty = + Button.CommandProperty.AddOwner(new(enableDataValidation: true)); /// /// Defines the property. @@ -113,7 +110,6 @@ public class MenuItem : HeaderedSelectingItemsControl, IMenuItem, ISelectable, I private static readonly ITemplate DefaultPanel = new FuncTemplate(() => new StackPanel()); - private ICommand? _command; private bool _commandCanExecute = true; private bool _commandBindingError; private Popup? _popup; @@ -217,8 +213,8 @@ public event EventHandler? SubmenuOpened /// public ICommand? Command { - get { return _command; } - set { SetAndRaise(CommandProperty, ref _command, value); } + get => GetValue(CommandProperty); + set => SetValue(CommandProperty, value); } /// @@ -337,7 +333,7 @@ public bool StaysOpenOnClick /// /// This has the same effect as setting to true. /// - public void Open() => IsSubMenuOpen = true; + public void Open() => SetCurrentValue(IsSubMenuOpenProperty, true); /// /// Closes the submenu. @@ -345,7 +341,7 @@ public bool StaysOpenOnClick /// /// This has the same effect as setting to false. /// - public void Close() => IsSubMenuOpen = false; + public void Close() => SetCurrentValue(IsSubMenuOpenProperty, false); /// void IMenuItem.RaiseClick() => RaiseEvent(new RoutedEventArgs(ClickEvent)); @@ -369,7 +365,7 @@ protected override void OnAttachedToLogicalTree(LogicalTreeAttachmentEventArgs e { if (_hotkey != null) // Control attached again, set Hotkey to create a hotkey manager for this control { - HotKey = _hotkey; + SetCurrentValue(HotKeyProperty, _hotkey); } base.OnAttachedToLogicalTree(e); @@ -397,7 +393,7 @@ protected override void OnDetachedFromLogicalTree(LogicalTreeAttachmentEventArgs if (HotKey != null) { _hotkey = HotKey; - HotKey = null; + SetCurrentValue(HotKeyProperty, null); } base.OnDetachedFromLogicalTree(e); @@ -663,7 +659,7 @@ private void SubMenuOpenChanged(AvaloniaPropertyChangedEventArgs e) } RaiseEvent(new RoutedEventArgs(SubmenuOpenedEvent)); - IsSelected = true; + SetCurrentValue(IsSelectedProperty, true); PseudoClasses.Add(":open"); } else diff --git a/src/Avalonia.Controls/NativeMenu.cs b/src/Avalonia.Controls/NativeMenu.cs index 5ff4148e5ab..7b03c607b69 100644 --- a/src/Avalonia.Controls/NativeMenu.cs +++ b/src/Avalonia.Controls/NativeMenu.cs @@ -79,12 +79,12 @@ private void ItemsChanged(object? sender, NotifyCollectionChangedEventArgs e) } public static readonly DirectProperty ParentProperty = - AvaloniaProperty.RegisterDirect("Parent", o => o.Parent, (o, v) => o.Parent = v); + AvaloniaProperty.RegisterDirect(nameof(Parent), o => o.Parent); public NativeMenuItem? Parent { get => _parent; - set => SetAndRaise(ParentProperty, ref _parent, value); + internal set => SetAndRaise(ParentProperty, ref _parent, value); } public void Add(NativeMenuItemBase item) => _items.Add(item); diff --git a/src/Avalonia.Controls/NativeMenuItem.cs b/src/Avalonia.Controls/NativeMenuItem.cs index 32fa574ee6f..9b5f756887f 100644 --- a/src/Avalonia.Controls/NativeMenuItem.cs +++ b/src/Avalonia.Controls/NativeMenuItem.cs @@ -4,36 +4,13 @@ using Avalonia.Media.Imaging; using Avalonia.Metadata; using Avalonia.Utilities; -using Avalonia.Reactive; namespace Avalonia.Controls { public class NativeMenuItem : NativeMenuItemBase, INativeMenuItemExporterEventsImplBridge { - private string? _header; - private KeyGesture? _gesture; - private bool _isEnabled = true; - private ICommand? _command; - private bool _isChecked = false; - private NativeMenuItemToggleType _toggleType; - private IBitmap? _icon; private readonly CanExecuteChangedSubscriber _canExecuteChangedSubscriber; - private NativeMenu? _menu; - - static NativeMenuItem() - { - MenuProperty.Changed.Subscribe(args => - { - var item = (NativeMenuItem)args.Sender; - var value = args.NewValue.GetValueOrDefault()!; - if (value.Parent != null && value.Parent != item) - throw new InvalidOperationException("NativeMenu already has a parent"); - value.Parent = item; - }); - } - - class CanExecuteChangedSubscriber : IWeakEventSubscriber { private readonly NativeMenuItem _parent; @@ -60,78 +37,70 @@ public NativeMenuItem(string header) : this() Header = header; } - public static readonly DirectProperty MenuProperty = - AvaloniaProperty.RegisterDirect(nameof(Menu), o => o.Menu, (o, v) => o.Menu = v); + public static readonly StyledProperty MenuProperty = + AvaloniaProperty.Register(nameof(Menu), coerce: CoerceMenu); [Content] public NativeMenu? Menu { - get => _menu; - set - { - if (value != null && value.Parent != null && value.Parent != this) - throw new InvalidOperationException("NativeMenu already has a parent"); - SetAndRaise(MenuProperty, ref _menu, value); - } + get => GetValue(MenuProperty); + set => SetValue(MenuProperty, value); } - public static readonly DirectProperty IconProperty = - AvaloniaProperty.RegisterDirect(nameof(Icon), o => o.Icon, (o, v) => o.Icon = v); + private static NativeMenu? CoerceMenu(AvaloniaObject sender, NativeMenu? value) + { + if (value != null && value.Parent != null && value.Parent != sender) + throw new InvalidOperationException("NativeMenu already has a parent"); + return value; + } + public static readonly StyledProperty IconProperty = + AvaloniaProperty.Register(nameof(Icon)); public IBitmap? Icon { - get => _icon; - set => SetAndRaise(IconProperty, ref _icon, value); + get => GetValue(IconProperty); + set => SetValue(IconProperty, value); } - public static readonly DirectProperty HeaderProperty = - AvaloniaProperty.RegisterDirect(nameof(Header), o => o.Header, (o, v) => o.Header = v); + public static readonly StyledProperty HeaderProperty = + AvaloniaProperty.Register(nameof(Header)); public string? Header { - get => _header; - set => SetAndRaise(HeaderProperty, ref _header, value); + get => GetValue(HeaderProperty); + set => SetValue(HeaderProperty, value); } - public static readonly DirectProperty GestureProperty = - AvaloniaProperty.RegisterDirect(nameof(Gesture), o => o.Gesture, (o, v) => o.Gesture = v); + public static readonly StyledProperty GestureProperty = + AvaloniaProperty.Register(nameof(Gesture)); public KeyGesture? Gesture { - get => _gesture; - set => SetAndRaise(GestureProperty, ref _gesture, value); + get => GetValue(GestureProperty); + set => SetValue(GestureProperty, value); } - public static readonly DirectProperty IsCheckedProperty = - AvaloniaProperty.RegisterDirect( - nameof(IsChecked), - o => o.IsChecked, - (o, v) => o.IsChecked = v); + public static readonly StyledProperty IsCheckedProperty = + AvaloniaProperty.Register(nameof(IsChecked)); public bool IsChecked { - get => _isChecked; - set => SetAndRaise(IsCheckedProperty, ref _isChecked, value); + get => GetValue(IsCheckedProperty); + set => SetValue(IsCheckedProperty, value); } - public static readonly DirectProperty ToggleTypeProperty = - AvaloniaProperty.RegisterDirect( - nameof(ToggleType), - o => o.ToggleType, - (o, v) => o.ToggleType = v); + public static readonly StyledProperty ToggleTypeProperty = + AvaloniaProperty.Register(nameof(ToggleType)); public NativeMenuItemToggleType ToggleType { - get => _toggleType; - set => SetAndRaise(ToggleTypeProperty, ref _toggleType, value); + get => GetValue(ToggleTypeProperty); + set => SetValue(ToggleTypeProperty, value); } - public static readonly DirectProperty CommandProperty = - Button.CommandProperty.AddOwner( - menuItem => menuItem.Command, - (menuItem, command) => menuItem.Command = command, - enableDataValidation: true); + public static readonly StyledProperty CommandProperty = + Button.CommandProperty.AddOwner(new(enableDataValidation: true)); /// /// Defines the property. @@ -139,37 +108,26 @@ public NativeMenuItemToggleType ToggleType public static readonly StyledProperty CommandParameterProperty = Button.CommandParameterProperty.AddOwner(); - public static readonly DirectProperty IsEnabledProperty = - AvaloniaProperty.RegisterDirect(nameof(IsEnabled), o => o.IsEnabled, (o, v) => o.IsEnabled = v, true); + public static readonly StyledProperty IsEnabledProperty = + AvaloniaProperty.Register(nameof(IsEnabled), true); public bool IsEnabled { - get => _isEnabled; - set => SetAndRaise(IsEnabledProperty, ref _isEnabled, value); + get => GetValue(IsEnabledProperty); + set => SetValue(IsEnabledProperty, value); } void CanExecuteChanged() { - IsEnabled = _command?.CanExecute(CommandParameter) ?? true; + SetCurrentValue(IsEnabledProperty, Command?.CanExecute(CommandParameter) ?? true); } public bool HasClickHandlers => Click != null; public ICommand? Command { - get => _command; - set - { - if (_command != null) - WeakEvents.CommandCanExecuteChanged.Unsubscribe(_command, _canExecuteChangedSubscriber); - - SetAndRaise(CommandProperty, ref _command, value); - - if (_command != null) - WeakEvents.CommandCanExecuteChanged.Subscribe(_command, _canExecuteChangedSubscriber); - - CanExecuteChanged(); - } + get => GetValue(CommandProperty); + set => SetValue(CommandProperty, value); } /// @@ -196,8 +154,28 @@ void INativeMenuItemExporterEventsImplBridge.RaiseClicked() Command.Execute(CommandParameter); } } + + protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) + { + base.OnPropertyChanged(change); + + if (change.Property == MenuProperty && change.NewValue is NativeMenu newMenu) + { + if (newMenu.Parent != null && newMenu.Parent != this) + throw new InvalidOperationException("NativeMenu already has a parent"); + newMenu.Parent = this; + } + else if (change.Property == CommandProperty) + { + if (change.OldValue is ICommand oldCommand) + WeakEvents.CommandCanExecuteChanged.Unsubscribe(oldCommand, _canExecuteChangedSubscriber); + if (change.NewValue is ICommand newCommand) + WeakEvents.CommandCanExecuteChanged.Subscribe(newCommand, _canExecuteChangedSubscriber); + CanExecuteChanged(); + } + } } - + public enum NativeMenuItemToggleType { None, diff --git a/src/Avalonia.Controls/NativeMenuItemBase.cs b/src/Avalonia.Controls/NativeMenuItemBase.cs index 4946d16f010..70cb2b806e0 100644 --- a/src/Avalonia.Controls/NativeMenuItemBase.cs +++ b/src/Avalonia.Controls/NativeMenuItemBase.cs @@ -12,12 +12,12 @@ internal NativeMenuItemBase() } public static readonly DirectProperty ParentProperty = - AvaloniaProperty.RegisterDirect("Parent", o => o.Parent, (o, v) => o.Parent = v); + AvaloniaProperty.RegisterDirect(nameof(Parent), o => o.Parent); public NativeMenu? Parent { get => _parent; - set => SetAndRaise(ParentProperty, ref _parent, value); + internal set => SetAndRaise(ParentProperty, ref _parent, value); } } } diff --git a/src/Avalonia.Controls/Notifications/NotificationCard.cs b/src/Avalonia.Controls/Notifications/NotificationCard.cs index 663bd3358a8..705d40380e2 100644 --- a/src/Avalonia.Controls/Notifications/NotificationCard.cs +++ b/src/Avalonia.Controls/Notifications/NotificationCard.cs @@ -13,7 +13,6 @@ namespace Avalonia.Controls.Notifications [PseudoClasses(":error", ":information", ":success", ":warning")] public class NotificationCard : ContentControl { - private bool _isClosed; private bool _isClosing; static NotificationCard() @@ -84,15 +83,15 @@ public bool IsClosing /// public bool IsClosed { - get { return _isClosed; } - set { SetAndRaise(IsClosedProperty, ref _isClosed, value); } + get => GetValue(IsClosedProperty); + set => SetValue(IsClosedProperty, value); } /// /// Defines the property. /// - public static readonly DirectProperty IsClosedProperty = - AvaloniaProperty.RegisterDirect(nameof(IsClosed), o => o.IsClosed, (o, v) => o.IsClosed = v); + public static readonly StyledProperty IsClosedProperty = + AvaloniaProperty.Register(nameof(IsClosed)); /// /// Defines the event. diff --git a/src/Avalonia.Controls/NumericUpDown/NumericUpDown.cs b/src/Avalonia.Controls/NumericUpDown/NumericUpDown.cs index ac4f6993134..885a8af5d13 100644 --- a/src/Avalonia.Controls/NumericUpDown/NumericUpDown.cs +++ b/src/Avalonia.Controls/NumericUpDown/NumericUpDown.cs @@ -43,16 +43,14 @@ public class NumericUpDown : TemplatedControl /// /// Defines the property. /// - public static readonly DirectProperty ClipValueToMinMaxProperty = - AvaloniaProperty.RegisterDirect(nameof(ClipValueToMinMax), - updown => updown.ClipValueToMinMax, (updown, b) => updown.ClipValueToMinMax = b); + public static readonly StyledProperty ClipValueToMinMaxProperty = + AvaloniaProperty.Register(nameof(ClipValueToMinMax)); /// /// Defines the property. /// - public static readonly DirectProperty NumberFormatProperty = - AvaloniaProperty.RegisterDirect(nameof(NumberFormat), o => o.NumberFormat, - (o, v) => o.NumberFormat = v, NumberFormatInfo.CurrentInfo); + public static readonly StyledProperty NumberFormatProperty = + AvaloniaProperty.Register(nameof(NumberFormat), NumberFormatInfo.CurrentInfo); /// /// Defines the property. @@ -87,30 +85,28 @@ public class NumericUpDown : TemplatedControl /// /// Defines the property. /// - public static readonly DirectProperty ParsingNumberStyleProperty = - AvaloniaProperty.RegisterDirect(nameof(ParsingNumberStyle), - updown => updown.ParsingNumberStyle, (updown, style) => updown.ParsingNumberStyle = style); + public static readonly StyledProperty ParsingNumberStyleProperty = + AvaloniaProperty.Register(nameof(ParsingNumberStyle), NumberStyles.Any); /// /// Defines the property. /// - public static readonly DirectProperty TextProperty = - AvaloniaProperty.RegisterDirect(nameof(Text), o => o.Text, (o, v) => o.Text = v, + public static readonly StyledProperty TextProperty = + AvaloniaProperty.Register(nameof(Text), defaultBindingMode: BindingMode.TwoWay, enableDataValidation: true); /// /// Defines the property. /// - public static readonly DirectProperty TextConverterProperty = - AvaloniaProperty.RegisterDirect(nameof(TextConverter), - updown => updown.TextConverter, (o, v) => o.TextConverter = v, null, BindingMode.OneWay, false); + public static readonly StyledProperty TextConverterProperty = + AvaloniaProperty.Register(nameof(TextConverter), defaultBindingMode: BindingMode.OneWay); /// /// Defines the property. /// - public static readonly DirectProperty ValueProperty = - AvaloniaProperty.RegisterDirect(nameof(Value), updown => updown.Value, - (updown, v) => updown.Value = v, defaultBindingMode: BindingMode.TwoWay, enableDataValidation: true); + public static readonly StyledProperty ValueProperty = + AvaloniaProperty.Register(nameof(Value), coerce: (s,v) => ((NumericUpDown)s).OnCoerceValue(v), + defaultBindingMode: BindingMode.TwoWay, enableDataValidation: true); /// /// Defines the property. @@ -132,15 +128,9 @@ public class NumericUpDown : TemplatedControl private IDisposable? _textBoxTextChangedSubscription; - private decimal? _value; - private string? _text; - private IValueConverter? _textConverter; private bool _internalValueSet; - private bool _clipValueToMinMax; private bool _isSyncingTextAndValueProperties; private bool _isTextChangedFromUI; - private NumberStyles _parsingNumberStyle = NumberStyles.Any; - private NumberFormatInfo? _numberFormat; /// /// Gets the Spinner template part. @@ -184,8 +174,8 @@ public bool ShowButtonSpinner /// public bool ClipValueToMinMax { - get { return _clipValueToMinMax; } - set { SetAndRaise(ClipValueToMinMaxProperty, ref _clipValueToMinMax, value); } + get => GetValue(ClipValueToMinMaxProperty); + set => SetValue(ClipValueToMinMaxProperty, value); } /// @@ -193,8 +183,8 @@ public bool ClipValueToMinMax /// public NumberFormatInfo? NumberFormat { - get { return _numberFormat; } - set { SetAndRaise(NumberFormatProperty, ref _numberFormat, value); } + get => GetValue(NumberFormatProperty); + set => SetValue(NumberFormatProperty, value); } /// @@ -249,8 +239,8 @@ public decimal Minimum /// public NumberStyles ParsingNumberStyle { - get { return _parsingNumberStyle; } - set { SetAndRaise(ParsingNumberStyleProperty, ref _parsingNumberStyle, value); } + get => GetValue(ParsingNumberStyleProperty); + set => SetValue(ParsingNumberStyleProperty, value); } /// @@ -258,8 +248,8 @@ public NumberStyles ParsingNumberStyle /// public string? Text { - get { return _text; } - set { SetAndRaise(TextProperty, ref _text, value); } + get => GetValue(TextProperty); + set => SetValue(TextProperty, value); } /// @@ -269,8 +259,8 @@ public string? Text /// public IValueConverter? TextConverter { - get { return _textConverter; } - set { SetAndRaise(TextConverterProperty, ref _textConverter, value); } + get => GetValue(TextConverterProperty); + set => SetValue(TextConverterProperty, value); } /// @@ -278,12 +268,8 @@ public IValueConverter? TextConverter /// public decimal? Value { - get { return _value; } - set - { - value = OnCoerceValue(value); - SetAndRaise(ValueProperty, ref _value, value); - } + get => GetValue(ValueProperty); + set => SetValue(ValueProperty, value); } /// @@ -475,7 +461,7 @@ protected virtual void OnMaximumChanged(decimal oldValue, decimal newValue) } if (ClipValueToMinMax && Value.HasValue) { - Value = MathUtilities.Clamp(Value.Value, Minimum, Maximum); + SetCurrentValue(ValueProperty, MathUtilities.Clamp(Value.Value, Minimum, Maximum)); } } @@ -492,7 +478,7 @@ protected virtual void OnMinimumChanged(decimal oldValue, decimal newValue) } if (ClipValueToMinMax && Value.HasValue) { - Value = MathUtilities.Clamp(Value.Value, Minimum, Maximum); + SetCurrentValue(ValueProperty, MathUtilities.Clamp(Value.Value, Minimum, Maximum)); } } @@ -508,7 +494,7 @@ protected virtual void OnTextChanged(string? oldValue, string? newValue) SyncTextAndValueProperties(true, Text); } } - + /// /// Called when the property value changed. /// @@ -675,8 +661,8 @@ private void OnIncrement() { result = Minimum; } - - Value = MathUtilities.Clamp(result, Minimum, Maximum); + + SetCurrentValue(ValueProperty, MathUtilities.Clamp(result, Minimum, Maximum)); } /// @@ -685,7 +671,7 @@ private void OnIncrement() private void OnDecrement() { decimal result; - + if (Value.HasValue) { result = Value.Value - Increment; @@ -694,8 +680,8 @@ private void OnDecrement() { result = Maximum; } - - Value = MathUtilities.Clamp(result, Minimum, Maximum); + + SetCurrentValue(ValueProperty, MathUtilities.Clamp(result, Minimum, Maximum)); } /// @@ -712,7 +698,7 @@ private void SetValidSpinDirection() { validDirections = ValidSpinDirections.Increase | ValidSpinDirections.Decrease; } - + if (Value < Maximum) { validDirections = validDirections | ValidSpinDirections.Increase; @@ -862,7 +848,7 @@ private void SetValueInternal(decimal? value) _internalValueSet = true; try { - Value = value; + SetCurrentValue(ValueProperty, value); } finally { @@ -907,7 +893,7 @@ private void TextBoxOnTextChanged() _isTextChangedFromUI = true; if (TextBox != null) { - Text = TextBox.Text; + SetCurrentValue(TextProperty, TextBox.Text); } } finally @@ -1026,7 +1012,7 @@ private bool SyncTextAndValueProperties(bool updateValueFromText, string? text, var newText = ConvertValueToText(); if (!Equals(Text, newText)) { - Text = newText; + SetCurrentValue(TextProperty, newText); } } @@ -1066,7 +1052,7 @@ private bool SyncTextAndValueProperties(bool updateValueFromText, string? text, { return null; } - + if (TextConverter != null) { var valueFromText = TextConverter.Convert(text, typeof(decimal?), null, CultureInfo.CurrentCulture); diff --git a/src/Avalonia.Controls/Presenters/ContentPresenter.cs b/src/Avalonia.Controls/Presenters/ContentPresenter.cs index be61bb18a18..329a0fa6aba 100644 --- a/src/Avalonia.Controls/Presenters/ContentPresenter.cs +++ b/src/Avalonia.Controls/Presenters/ContentPresenter.cs @@ -156,16 +156,13 @@ public class ContentPresenter : Control, IContentPresenter /// /// Defines the property /// - public static readonly DirectProperty RecognizesAccessKeyProperty = - AvaloniaProperty.RegisterDirect( - nameof(RecognizesAccessKey), - cp => cp.RecognizesAccessKey, (cp, value) => cp.RecognizesAccessKey = value); + public static readonly StyledProperty RecognizesAccessKeyProperty = + AvaloniaProperty.Register(nameof(RecognizesAccessKey)); private Control? _child; private bool _createdChild; private IRecyclingDataTemplate? _recyclingDataTemplate; private readonly BorderRenderHelper _borderRenderer = new BorderRenderHelper(); - private bool _recognizesAccessKey; /// /// Initializes static members of the class. @@ -386,8 +383,8 @@ public Thickness Padding /// public bool RecognizesAccessKey { - get => _recognizesAccessKey; - set => SetAndRaise(RecognizesAccessKeyProperty, ref _recognizesAccessKey, value); + get => GetValue(RecognizesAccessKeyProperty); + set => SetValue(RecognizesAccessKeyProperty, value); } /// diff --git a/src/Avalonia.Controls/Presenters/ItemsPresenter.cs b/src/Avalonia.Controls/Presenters/ItemsPresenter.cs index 0a762c438d9..a0020a0b6ea 100644 --- a/src/Avalonia.Controls/Presenters/ItemsPresenter.cs +++ b/src/Avalonia.Controls/Presenters/ItemsPresenter.cs @@ -166,7 +166,7 @@ public override sealed void ApplyTemplate() } Panel = ItemsPanel.Build(); - Panel.SetValue(TemplatedParentProperty, TemplatedParent); + Panel.TemplatedParent = TemplatedParent; Panel.IsItemsHost = true; _scrollSnapPointsInfo = Panel as IScrollSnapPointsInfo; LogicalChildren.Add(Panel); diff --git a/src/Avalonia.Controls/Primitives/Popup.cs b/src/Avalonia.Controls/Primitives/Popup.cs index 9d443d92897..0c6c4347131 100644 --- a/src/Avalonia.Controls/Primitives/Popup.cs +++ b/src/Avalonia.Controls/Primitives/Popup.cs @@ -2,7 +2,6 @@ using System.ComponentModel; using Avalonia.Reactive; using Avalonia.Automation.Peers; -using Avalonia.Controls.Mixins; using Avalonia.Controls.Diagnostics; using Avalonia.Controls.Presenters; using Avalonia.Controls.Primitives.PopupPositioning; @@ -41,11 +40,8 @@ public class Popup : Control, IPopupHostProvider /// /// Defines the property. /// - public static readonly DirectProperty IsOpenProperty = - AvaloniaProperty.RegisterDirect( - nameof(IsOpen), - o => o.IsOpen, - (o, v) => o.IsOpen = v); + public static readonly StyledProperty IsOpenProperty = + AvaloniaProperty.Register(nameof(IsOpen)); /// /// Defines the property. @@ -90,11 +86,8 @@ public class Popup : Control, IPopupHostProvider public static readonly StyledProperty OverlayDismissEventPassThroughProperty = AvaloniaProperty.Register(nameof(OverlayDismissEventPassThrough)); - public static readonly DirectProperty OverlayInputPassThroughElementProperty = - AvaloniaProperty.RegisterDirect( - nameof(OverlayInputPassThroughElement), - o => o.OverlayInputPassThroughElement, - (o, v) => o.OverlayInputPassThroughElement = v); + public static readonly StyledProperty OverlayInputPassThroughElementProperty = + AvaloniaProperty.Register(nameof(OverlayInputPassThroughElement)); /// /// Defines the property. @@ -121,10 +114,8 @@ public class Popup : Control, IPopupHostProvider AvaloniaProperty.Register(nameof(Topmost)); private bool _isOpenRequested; - private bool _isOpen; private bool _ignoreIsOpenChanged; private PopupOpenState? _openState; - private IInputElement? _overlayInputPassThroughElement; private Action? _popupHostChangedHandler; /// @@ -209,8 +200,8 @@ public bool IsLightDismissEnabled /// public bool IsOpen { - get { return _isOpen; } - set { SetAndRaise(IsOpenProperty, ref _isOpen, value); } + get => GetValue(IsOpenProperty); + set => SetValue(IsOpenProperty, value); } /// @@ -301,8 +292,8 @@ public bool OverlayDismissEventPassThrough /// public IInputElement? OverlayInputPassThroughElement { - get => _overlayInputPassThroughElement; - set => SetAndRaise(OverlayInputPassThroughElementProperty, ref _overlayInputPassThroughElement, value); + get => GetValue(OverlayInputPassThroughElementProperty); + set => SetValue(OverlayInputPassThroughElementProperty, value); } /// @@ -486,7 +477,7 @@ public void Open() using (BeginIgnoringIsOpen()) { - IsOpen = true; + SetCurrentValue(IsOpenProperty, true); } Opened?.Invoke(this, EventArgs.Empty); @@ -704,7 +695,7 @@ private void CloseCore() { using (BeginIgnoringIsOpen()) { - IsOpen = false; + SetCurrentValue(IsOpenProperty, false); } return; @@ -717,7 +708,7 @@ private void CloseCore() using (BeginIgnoringIsOpen()) { - IsOpen = false; + SetCurrentValue(IsOpenProperty, false); } Closed?.Invoke(this, EventArgs.Empty); diff --git a/src/Avalonia.Controls/Primitives/TemplatedControl.cs b/src/Avalonia.Controls/Primitives/TemplatedControl.cs index 8253342782f..e1cf25d89f3 100644 --- a/src/Avalonia.Controls/Primitives/TemplatedControl.cs +++ b/src/Avalonia.Controls/Primitives/TemplatedControl.cs @@ -275,7 +275,7 @@ public sealed override void ApplyTemplate() { foreach (var child in this.GetTemplateChildren()) { - child.SetValue(TemplatedParentProperty, null); + child.TemplatedParent = null; ((ISetLogicalParent)child).SetParent(null); } @@ -377,7 +377,7 @@ protected virtual void OnTemplateChanged(AvaloniaPropertyChangedEventArgs e) /// The templated parent to apply. internal static void ApplyTemplatedParent(StyledElement control, AvaloniaObject? templatedParent) { - control.SetValue(TemplatedParentProperty, templatedParent); + control.TemplatedParent = templatedParent; var children = control.LogicalChildren; var count = children.Count; diff --git a/src/Avalonia.Controls/Primitives/ToggleButton.cs b/src/Avalonia.Controls/Primitives/ToggleButton.cs index 158c5d875bd..dfaf7bbc454 100644 --- a/src/Avalonia.Controls/Primitives/ToggleButton.cs +++ b/src/Avalonia.Controls/Primitives/ToggleButton.cs @@ -15,12 +15,8 @@ public class ToggleButton : Button /// /// Defines the property. /// - public static readonly DirectProperty IsCheckedProperty = - AvaloniaProperty.RegisterDirect( - nameof(IsChecked), - o => o.IsChecked, - (o, v) => o.IsChecked = v, - unsetValue: false, + public static readonly StyledProperty IsCheckedProperty = + AvaloniaProperty.Register(nameof(IsChecked), false, defaultBindingMode: BindingMode.TwoWay); /// @@ -64,8 +60,6 @@ public class ToggleButton : Button nameof(IsCheckedChanged), RoutingStrategies.Bubble); - private bool? _isChecked = false; - static ToggleButton() { } @@ -119,12 +113,8 @@ public event EventHandler? IsCheckedChanged /// public bool? IsChecked { - get => _isChecked; - set - { - SetAndRaise(IsCheckedProperty, ref _isChecked, value); - UpdatePseudoClasses(IsChecked); - } + get => GetValue(IsCheckedProperty); + set => SetValue(IsCheckedProperty, value); } /// @@ -147,28 +137,31 @@ protected override void OnClick() /// protected virtual void Toggle() { + bool? newValue; if (IsChecked.HasValue) { if (IsChecked.Value) { if (IsThreeState) { - IsChecked = null; + newValue = null; } else { - IsChecked = false; + newValue = false; } } else { - IsChecked = true; + newValue = true; } } else { - IsChecked = false; + newValue = false; } + + SetCurrentValue(IsCheckedProperty, newValue); } /// @@ -224,6 +217,8 @@ protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs chang { var newValue = change.GetNewValue(); + UpdatePseudoClasses(newValue); + #pragma warning disable CS0618 // Type or member is obsolete switch (newValue) { diff --git a/src/Avalonia.Controls/RadioButton.cs b/src/Avalonia.Controls/RadioButton.cs index 87772aced70..d4528fdb1ca 100644 --- a/src/Avalonia.Controls/RadioButton.cs +++ b/src/Avalonia.Controls/RadioButton.cs @@ -98,31 +98,22 @@ public void SetChecked(RadioButton radioButton) } } - public static readonly DirectProperty GroupNameProperty = - AvaloniaProperty.RegisterDirect( - nameof(GroupName), - o => o.GroupName, - (o, v) => o.GroupName = v); + public static readonly StyledProperty GroupNameProperty = + AvaloniaProperty.Register(nameof(GroupName)); - private string? _groupName; private RadioButtonGroupManager? _groupManager; - public RadioButton() - { - this.GetObservable(IsCheckedProperty).Subscribe(IsCheckedChanged); - } - public string? GroupName { - get { return _groupName; } - set { SetGroupName(value); } + get => GetValue(GroupNameProperty); + set => SetValue(GroupNameProperty, value); } protected override void Toggle() { if (!IsChecked.GetValueOrDefault()) { - IsChecked = true; + SetCurrentValue(IsCheckedProperty, true); } } @@ -154,28 +145,38 @@ protected override AutomationPeer OnCreateAutomationPeer() return new RadioButtonAutomationPeer(this); } - private void SetGroupName(string? newGroupName) + protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) { - var oldGroupName = GroupName; - if (newGroupName != oldGroupName) + base.OnPropertyChanged(change); + + if (change.Property == IsCheckedProperty) { - if (!string.IsNullOrEmpty(oldGroupName)) - { - _groupManager?.Remove(this, oldGroupName); - } - _groupName = newGroupName; - if (!string.IsNullOrEmpty(newGroupName)) + IsCheckedChanged(change.GetNewValue()); + } + else if (change.Property == GroupNameProperty) + { + var (oldValue, newValue) = change.GetOldAndNewValue(); + OnGroupNameChanged(oldValue, newValue); + } + } + + private void OnGroupNameChanged(string? oldGroupName, string? newGroupName) + { + if (!string.IsNullOrEmpty(oldGroupName)) + { + _groupManager?.Remove(this, oldGroupName); + } + if (!string.IsNullOrEmpty(newGroupName)) + { + if (_groupManager == null) { - if (_groupManager == null) - { - _groupManager = RadioButtonGroupManager.GetOrCreateForRoot(this.GetVisualRoot()); - } - _groupManager.Add(this); + _groupManager = RadioButtonGroupManager.GetOrCreateForRoot(this.GetVisualRoot()); } + _groupManager.Add(this); } } - private void IsCheckedChanged(bool? value) + private new void IsCheckedChanged(bool? value) { var groupName = GroupName; if (string.IsNullOrEmpty(groupName)) diff --git a/src/Avalonia.Controls/SplitButton/SplitButton.cs b/src/Avalonia.Controls/SplitButton/SplitButton.cs index 31a06d875ab..e82fb39a66c 100644 --- a/src/Avalonia.Controls/SplitButton/SplitButton.cs +++ b/src/Avalonia.Controls/SplitButton/SplitButton.cs @@ -42,10 +42,8 @@ public event EventHandler? Click /// /// Defines the property. /// - public static readonly DirectProperty CommandProperty = - Button.CommandProperty.AddOwner( - splitButton => splitButton.Command, - (splitButton, command) => splitButton.Command = command); + public static readonly StyledProperty CommandProperty = + Button.CommandProperty.AddOwner(); /// /// Defines the property. @@ -59,8 +57,6 @@ public event EventHandler? Click public static readonly StyledProperty FlyoutProperty = Button.FlyoutProperty.AddOwner(); - private ICommand? _Command; - private Button? _primaryButton = null; private Button? _secondaryButton = null; @@ -83,8 +79,8 @@ public SplitButton() /// public ICommand? Command { - get => _Command; - set => SetAndRaise(CommandProperty, ref _Command, value); + get => GetValue(CommandProperty); + set => SetValue(CommandProperty, value); } /// diff --git a/src/Avalonia.Controls/TrayIcon.cs b/src/Avalonia.Controls/TrayIcon.cs index 5713846b35d..73bcb84c69e 100644 --- a/src/Avalonia.Controls/TrayIcon.cs +++ b/src/Avalonia.Controls/TrayIcon.cs @@ -13,13 +13,10 @@ namespace Avalonia.Controls public sealed class TrayIcons : AvaloniaList { } - - public class TrayIcon : AvaloniaObject, INativeMenuExporterProvider, IDisposable { private readonly ITrayIconImpl? _impl; - private ICommand? _command; private TrayIcon(ITrayIconImpl? impl) { @@ -85,11 +82,8 @@ static TrayIcon() /// /// Defines the property. /// - public static readonly DirectProperty CommandProperty = - Button.CommandProperty.AddOwner( - trayIcon => trayIcon.Command, - (trayIcon, command) => trayIcon.Command = command, - enableDataValidation: true); + public static readonly StyledProperty CommandProperty = + Button.CommandProperty.AddOwner(new(enableDataValidation: true)); /// /// Defines the property. @@ -136,8 +130,8 @@ public static readonly StyledProperty MenuProperty /// public ICommand? Command { - get => _command; - set => SetAndRaise(CommandProperty, ref _command, value); + get => GetValue(CommandProperty); + set => SetValue(CommandProperty, value); } /// diff --git a/src/Avalonia.Controls/TreeViewItem.cs b/src/Avalonia.Controls/TreeViewItem.cs index e9abfef6730..3ac157f7271 100644 --- a/src/Avalonia.Controls/TreeViewItem.cs +++ b/src/Avalonia.Controls/TreeViewItem.cs @@ -104,12 +104,12 @@ protected override void OnAttachedToLogicalTree(LogicalTreeAttachmentEventArgs e if (ItemTemplate == null && _treeView?.ItemTemplate != null) { - ItemTemplate = _treeView.ItemTemplate; + SetCurrentValue(ItemTemplateProperty, _treeView.ItemTemplate); } if (ItemContainerTheme == null && _treeView?.ItemContainerTheme != null) { - ItemContainerTheme = _treeView.ItemContainerTheme; + SetCurrentValue(ItemContainerThemeProperty, _treeView.ItemContainerTheme); } } diff --git a/src/Avalonia.Controls/Window.cs b/src/Avalonia.Controls/Window.cs index ba1b5994218..f9593f1c1b8 100644 --- a/src/Avalonia.Controls/Window.cs +++ b/src/Avalonia.Controls/Window.cs @@ -1,8 +1,6 @@ using System; using System.Collections.Generic; -using System.ComponentModel; using System.Linq; -using Avalonia.Reactive; using System.Threading.Tasks; using Avalonia.Automation.Peers; using Avalonia.Controls.Platform; @@ -11,6 +9,7 @@ using Avalonia.Layout; using Avalonia.Media; using Avalonia.Platform; +using Avalonia.Reactive; using Avalonia.Styling; namespace Avalonia.Controls @@ -149,11 +148,8 @@ public class Window : WindowBase, IStyleable, IFocusScope, ILayoutRoot /// /// Defines the property. /// - public static readonly DirectProperty WindowStartupLocationProperty = - AvaloniaProperty.RegisterDirect( - nameof(WindowStartupLocation), - o => o.WindowStartupLocation, - (o, v) => o.WindowStartupLocation = v); + public static readonly StyledProperty WindowStartupLocationProperty = + AvaloniaProperty.Register(nameof(WindowStartupLocation)); public static readonly StyledProperty CanResizeProperty = AvaloniaProperty.Register(nameof(CanResize), true); @@ -171,7 +167,6 @@ public class Window : WindowBase, IStyleable, IFocusScope, ILayoutRoot RoutedEvent.Register("WindowOpened", RoutingStrategies.Direct); private object? _dialogResult; private readonly Size _maxPlatformClientSize; - private WindowStartupLocation _windowStartupLocation; private bool _shown; private bool _showingAsDialog; @@ -305,7 +300,7 @@ public double ExtendClientAreaTitleBarHeightHint { get => GetValue(ExtendClientAreaTitleBarHeightHintProperty); set => SetValue(ExtendClientAreaTitleBarHeightHintProperty, value); - } + } /// /// Gets if the ClientArea is Extended into the Window Decorations. @@ -314,7 +309,7 @@ public bool IsExtendedIntoWindowDecorations { get => _isExtendedIntoWindowDecorations; private set => SetAndRaise(IsExtendedIntoWindowDecorationsProperty, ref _isExtendedIntoWindowDecorations, value); - } + } /// /// Gets the WindowDecorationMargin. @@ -324,7 +319,7 @@ public Thickness WindowDecorationMargin { get => _windowDecorationMargin; private set => SetAndRaise(WindowDecorationMarginProperty, ref _windowDecorationMargin, value); - } + } /// /// Gets the window margin that is hidden off the screen area. @@ -397,8 +392,8 @@ public WindowIcon? Icon /// public WindowStartupLocation WindowStartupLocation { - get { return _windowStartupLocation; } - set { SetAndRaise(WindowStartupLocationProperty, ref _windowStartupLocation, value); } + get => GetValue(WindowStartupLocationProperty); + set => SetValue(WindowStartupLocationProperty, value); } /// @@ -488,7 +483,7 @@ private protected virtual bool HandleClosing(WindowCloseReason reason) CloseInternal(); return false; } - + return true; } @@ -614,7 +609,7 @@ protected override void IsVisibleChanged(AvaloniaPropertyChangedEventArgs e) if (_shown != isVisible) { - if(!_shown) + if (!_shown) { Show(); } @@ -657,7 +652,7 @@ private void EnsureStateBeforeShow() throw new InvalidOperationException("Cannot re-show a closed window."); } } - + private void EnsureParentStateBeforeShow(Window owner) { if (owner.PlatformImpl == null) @@ -819,7 +814,7 @@ private void UpdateEnabled() { bool isEnabled = true; - foreach (var (_, isDialog) in _children) + foreach (var (_, isDialog) in _children) { if (isDialog) { @@ -856,7 +851,7 @@ private void OnGotInputWhenDisabled() { Window? firstDialogChild = null; - foreach (var (child, isDialog) in _children) + foreach (var (child, isDialog) in _children) { if (isDialog) { @@ -880,7 +875,7 @@ private void SetWindowStartupLocation(IWindowBaseImpl? owner = null) var startupLocation = WindowStartupLocation; if (startupLocation == WindowStartupLocation.CenterOwner && - (owner is null || + (owner is null || (Owner is Window ownerWindow && ownerWindow.WindowState == WindowState.Minimized)) ) { @@ -902,7 +897,7 @@ private void SetWindowStartupLocation(IWindowBaseImpl? owner = null) if (owner is not null) { - screen = Screens.ScreenFromWindow(owner) + screen = Screens.ScreenFromWindow(owner) ?? Screens.ScreenFromPoint(owner.Position); } diff --git a/src/Avalonia.Controls/WindowBase.cs b/src/Avalonia.Controls/WindowBase.cs index 26e11f0d4a8..814a9b59604 100644 --- a/src/Avalonia.Controls/WindowBase.cs +++ b/src/Avalonia.Controls/WindowBase.cs @@ -27,10 +27,7 @@ public class WindowBase : TopLevel /// Defines the property. /// public static readonly DirectProperty OwnerProperty = - AvaloniaProperty.RegisterDirect( - nameof(Owner), - o => o.Owner, - (o, v) => o.Owner = v); + AvaloniaProperty.RegisterDirect(nameof(Owner), o => o.Owner); public static readonly StyledProperty TopmostProperty = AvaloniaProperty.Register(nameof(Topmost)); diff --git a/src/Avalonia.Diagnostics/Diagnostics/Controls/ThicknessEditor.cs b/src/Avalonia.Diagnostics/Diagnostics/Controls/ThicknessEditor.cs index c9189a886d7..f765871ee85 100644 --- a/src/Avalonia.Diagnostics/Diagnostics/Controls/ThicknessEditor.cs +++ b/src/Avalonia.Diagnostics/Diagnostics/Controls/ThicknessEditor.cs @@ -6,84 +6,73 @@ namespace Avalonia.Diagnostics.Controls { internal class ThicknessEditor : ContentControl { - public static readonly DirectProperty ThicknessProperty = - AvaloniaProperty.RegisterDirect(nameof(Thickness), o => o.Thickness, - (o, v) => o.Thickness = v, defaultBindingMode: BindingMode.TwoWay); + public static readonly StyledProperty ThicknessProperty = + AvaloniaProperty.Register(nameof(Thickness), + defaultBindingMode: BindingMode.TwoWay); - public static readonly DirectProperty HeaderProperty = - AvaloniaProperty.RegisterDirect(nameof(Header), o => o.Header, - (o, v) => o.Header = v); + public static readonly StyledProperty HeaderProperty = + AvaloniaProperty.Register(nameof(Header)); - public static readonly DirectProperty IsPresentProperty = - AvaloniaProperty.RegisterDirect(nameof(IsPresent), o => o.IsPresent, - (o, v) => o.IsPresent = v); + public static readonly StyledProperty IsPresentProperty = + AvaloniaProperty.Register(nameof(IsPresent), true); - public static readonly DirectProperty LeftProperty = - AvaloniaProperty.RegisterDirect(nameof(Left), o => o.Left, (o, v) => o.Left = v); + public static readonly StyledProperty LeftProperty = + AvaloniaProperty.Register(nameof(Left)); - public static readonly DirectProperty TopProperty = - AvaloniaProperty.RegisterDirect(nameof(Top), o => o.Top, (o, v) => o.Top = v); + public static readonly StyledProperty TopProperty = + AvaloniaProperty.Register(nameof(Top)); - public static readonly DirectProperty RightProperty = - AvaloniaProperty.RegisterDirect(nameof(Right), o => o.Right, - (o, v) => o.Right = v); + public static readonly StyledProperty RightProperty = + AvaloniaProperty.Register(nameof(Right)); - public static readonly DirectProperty BottomProperty = - AvaloniaProperty.RegisterDirect(nameof(Bottom), o => o.Bottom, - (o, v) => o.Bottom = v); + public static readonly StyledProperty BottomProperty = + AvaloniaProperty.Register(nameof(Bottom)); public static readonly StyledProperty HighlightProperty = AvaloniaProperty.Register(nameof(Highlight)); - private Thickness _thickness; - private string? _header; - private bool _isPresent = true; - private double _left; - private double _top; - private double _right; - private double _bottom; private bool _isUpdatingThickness; public Thickness Thickness { - get => _thickness; - set => SetAndRaise(ThicknessProperty, ref _thickness, value); + get => GetValue(ThicknessProperty); + set => SetValue(ThicknessProperty, value); } public string? Header { - get => _header; - set => SetAndRaise(HeaderProperty, ref _header, value); + get => GetValue(HeaderProperty); + set => SetValue(HeaderProperty, value); } public bool IsPresent { - get => _isPresent; - set => SetAndRaise(IsPresentProperty, ref _isPresent, value); + get => GetValue(IsPresentProperty); + set => SetValue(IsPresentProperty, value); } public double Left { - get => _left; - set => SetAndRaise(LeftProperty, ref _left, value); + get => GetValue(LeftProperty); + set => SetValue(LeftProperty, value); } public double Top { - get => _top; - set => SetAndRaise(TopProperty, ref _top, value); + get => GetValue(TopProperty); + set => SetValue(TopProperty, value); } public double Right { - get => _right; - set => SetAndRaise(RightProperty, ref _right, value); + get => GetValue(RightProperty); + set => SetValue(RightProperty, value); } public double Bottom { - get => _bottom; - set => SetAndRaise(BottomProperty, ref _bottom, value); + get => GetValue(BottomProperty); + set => SetValue(BottomProperty, value); } public IBrush Highlight @@ -104,10 +93,10 @@ protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs chang var value = change.GetNewValue(); - Left = value.Left; - Top = value.Top; - Right = value.Right; - Bottom = value.Bottom; + SetCurrentValue(LeftProperty, value.Left); + SetCurrentValue(TopProperty, value.Top); + SetCurrentValue(RightProperty, value.Right); + SetCurrentValue(BottomProperty, value.Bottom); } finally { @@ -118,7 +107,7 @@ protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs chang (change.Property == LeftProperty || change.Property == TopProperty || change.Property == RightProperty || change.Property == BottomProperty)) { - Thickness = new Thickness(Left, Top, Right, Bottom); + SetCurrentValue(ThicknessProperty, new(Left, Top, Right, Bottom)); } } } diff --git a/src/Markup/Avalonia.Markup/Data/TemplateBinding.cs b/src/Markup/Avalonia.Markup/Data/TemplateBinding.cs index ba321db144a..cfb1b508d90 100644 --- a/src/Markup/Avalonia.Markup/Data/TemplateBinding.cs +++ b/src/Markup/Avalonia.Markup/Data/TemplateBinding.cs @@ -104,9 +104,7 @@ public TemplateBinding(AvaloniaProperty property) CultureInfo.CurrentCulture); } - // Use LocalValue priority here, as TemplatedParent doesn't make sense on controls - // that aren't template children. - templatedParent.SetValue(Property, value, BindingPriority.LocalValue); + templatedParent.SetCurrentValue(Property, value); } } diff --git a/tests/Avalonia.Base.UnitTests/Styling/SelectorTests_Template.cs b/tests/Avalonia.Base.UnitTests/Styling/SelectorTests_Template.cs index 738469bc6f7..75288155100 100644 --- a/tests/Avalonia.Base.UnitTests/Styling/SelectorTests_Template.cs +++ b/tests/Avalonia.Base.UnitTests/Styling/SelectorTests_Template.cs @@ -35,7 +35,7 @@ public void Control_Not_In_Template_Is_Not_Matched_With_Template_Selector() .Template() .OfType(); - border.SetValue(StyledElement.TemplatedParentProperty, null); + border.TemplatedParent = null; Assert.Equal(SelectorMatchResult.NeverThisInstance, selector.Match(border).Result); } @@ -124,10 +124,10 @@ public TestTemplatedControl() { VisualChildren.Add(new Border { - [TemplatedParentProperty] = this, + TemplatedParent = this, Child = new TextBlock { - [TemplatedParentProperty] = this, + TemplatedParent = this, }, }); } diff --git a/tests/Avalonia.Controls.UnitTests/ItemsControlTests.cs b/tests/Avalonia.Controls.UnitTests/ItemsControlTests.cs index 3aaf62f0bf5..7b5aa83b465 100644 --- a/tests/Avalonia.Controls.UnitTests/ItemsControlTests.cs +++ b/tests/Avalonia.Controls.UnitTests/ItemsControlTests.cs @@ -131,7 +131,7 @@ public void Container_Should_Have_LogicalParent_Set_To_ItemsControl() root.Content = target; var templatedParent = new Button(); - target.SetValue(StyledElement.TemplatedParentProperty, templatedParent); + target.TemplatedParent = templatedParent; target.Template = GetTemplate(); target.Items = new[] { "Foo" }; diff --git a/tests/Avalonia.Controls.UnitTests/Presenters/ContentPresenterTests_InTemplate.cs b/tests/Avalonia.Controls.UnitTests/Presenters/ContentPresenterTests_InTemplate.cs index d3737de45bb..9042e84fa1c 100644 --- a/tests/Avalonia.Controls.UnitTests/Presenters/ContentPresenterTests_InTemplate.cs +++ b/tests/Avalonia.Controls.UnitTests/Presenters/ContentPresenterTests_InTemplate.cs @@ -26,7 +26,7 @@ public void Should_Register_With_Host_When_TemplatedParent_Set() Assert.Null(host.Presenter); - target.SetValue(Control.TemplatedParentProperty, host); + target.TemplatedParent = host; Assert.Same(target, host.Presenter); } diff --git a/tests/Avalonia.Controls.UnitTests/Presenters/ItemsPresenterTests.cs b/tests/Avalonia.Controls.UnitTests/Presenters/ItemsPresenterTests.cs index 71f803fab7f..573ce5834dc 100644 --- a/tests/Avalonia.Controls.UnitTests/Presenters/ItemsPresenterTests.cs +++ b/tests/Avalonia.Controls.UnitTests/Presenters/ItemsPresenterTests.cs @@ -22,7 +22,7 @@ public void Should_Register_With_Host_When_TemplatedParent_Set() Assert.Null(host.Presenter); - target.SetValue(Control.TemplatedParentProperty, host); + target.TemplatedParent = host; Assert.Same(target, host.Presenter); } diff --git a/tests/Avalonia.Controls.UnitTests/Templates/TemplateExtensionsTests.cs b/tests/Avalonia.Controls.UnitTests/Templates/TemplateExtensionsTests.cs index 8789d79742f..33593a0631e 100644 --- a/tests/Avalonia.Controls.UnitTests/Templates/TemplateExtensionsTests.cs +++ b/tests/Avalonia.Controls.UnitTests/Templates/TemplateExtensionsTests.cs @@ -18,17 +18,17 @@ public void GetTemplateChildren_Should_Not_Return_Nested_Template_Controls() var border1 = new Border { Name = "border1", - [StyledElement.TemplatedParentProperty] = target, + TemplatedParent = target, }; var inner = new TestTemplatedControl { Name = "inner", - [StyledElement.TemplatedParentProperty] = target, + TemplatedParent = target, }; - var border2 = new Border { Name = "border2", [StyledElement.TemplatedParentProperty] = inner }; - var border3 = new Border { Name = "border3", [StyledElement.TemplatedParentProperty] = inner }; - var border4 = new Border { Name = "border4", [StyledElement.TemplatedParentProperty] = target }; - var border5 = new Border { Name = "border5", [StyledElement.TemplatedParentProperty] = null }; + var border2 = new Border { Name = "border2", TemplatedParent = inner }; + var border3 = new Border { Name = "border3", TemplatedParent = inner }; + var border4 = new Border { Name = "border4", TemplatedParent = target }; + var border5 = new Border { Name = "border5", TemplatedParent = null }; target.AddVisualChild(border1); border1.Child = inner; @@ -42,4 +42,4 @@ public void GetTemplateChildren_Should_Not_Return_Nested_Template_Controls() Assert.Equal(new[] { "border1", "inner", "border4" }, result); } } -} \ No newline at end of file +} diff --git a/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/XamlIlTests.cs b/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/XamlIlTests.cs index be2cae8ec4d..09ed78accb3 100644 --- a/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/XamlIlTests.cs +++ b/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/XamlIlTests.cs @@ -21,17 +21,6 @@ namespace Avalonia.Markup.Xaml.UnitTests { public class XamlIlTests : XamlTestBase { - [Fact] - public void Binding_Button_IsPressed_ShouldWork() - { - var parsed = (Button)AvaloniaRuntimeXamlLoader.Parse(@" -