diff --git a/src/Avalonia.Base/AttachedProperty.cs b/src/Avalonia.Base/AttachedProperty.cs index 31b6cad8ab..4a09f2a80a 100644 --- a/src/Avalonia.Base/AttachedProperty.cs +++ b/src/Avalonia.Base/AttachedProperty.cs @@ -32,9 +32,14 @@ namespace Avalonia /// /// 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 a202d6b5bc..3b9b2d0de6 100644 --- a/src/Avalonia.Base/Input/GestureRecognizers/GestureRecognizerCollection.cs +++ b/src/Avalonia.Base/Input/GestureRecognizers/GestureRecognizerCollection.cs @@ -2,7 +2,7 @@ using System.Collections; using System.Collections.Generic; using Avalonia.Controls; using Avalonia.LogicalTree; -using Avalonia.Styling; +using Avalonia.Reactive; namespace Avalonia.Input.GestureRecognizers { @@ -11,13 +11,13 @@ namespace Avalonia.Input.GestureRecognizers private readonly IInputElement _inputElement; private List? _recognizers; private Dictionary? _pointerGrabs; - - + + public GestureRecognizerCollection(IInputElement inputElement) { _inputElement = inputElement; } - + public void Add(IGestureRecognizer recognizer) { if (_recognizers == null) @@ -31,14 +31,13 @@ namespace Avalonia.Input.GestureRecognizers 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 @@ namespace Avalonia.Input.GestureRecognizers 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 991694cc60..6784677520 100644 --- a/src/Avalonia.Base/Input/GestureRecognizers/PullGestureRecognizer.cs +++ b/src/Avalonia.Base/Input/GestureRecognizers/PullGestureRecognizer.cs @@ -13,22 +13,18 @@ namespace Avalonia.Input 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 7c1ee13eed..1ad2f292ca 100644 --- a/src/Avalonia.Base/Input/GestureRecognizers/ScrollGestureRecognizer.cs +++ b/src/Avalonia.Base/Input/GestureRecognizers/ScrollGestureRecognizer.cs @@ -17,61 +17,45 @@ namespace Avalonia.Input.GestureRecognizers 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 @@ namespace Avalonia.Input.GestureRecognizers /// public bool CanVerticallyScroll { - get => _canVerticallyScroll; - set => SetAndRaise(CanVerticallyScrollProperty, ref _canVerticallyScroll, value); + get => GetValue(CanVerticallyScrollProperty); + set => SetValue(CanVerticallyScrollProperty, value); } /// @@ -88,8 +72,8 @@ namespace Avalonia.Input.GestureRecognizers /// public bool IsScrollInertiaEnabled { - get => _isScrollInertiaEnabled; - set => SetAndRaise(IsScrollInertiaEnabledProperty, ref _isScrollInertiaEnabled, value); + get => GetValue(IsScrollInertiaEnabledProperty); + set => SetValue(IsScrollInertiaEnabledProperty, value); } /// @@ -97,8 +81,8 @@ namespace Avalonia.Input.GestureRecognizers /// public int ScrollStartDistance { - get => _scrollStartDistance; - set => SetAndRaise(ScrollStartDistanceProperty, ref _scrollStartDistance, value); + get => GetValue(ScrollStartDistanceProperty); + set => SetValue(ScrollStartDistanceProperty, value); } @@ -137,8 +121,8 @@ namespace Avalonia.Input.GestureRecognizers // 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 525a543b70..8e57f9a902 100644 --- a/src/Avalonia.Base/Media/Imaging/CroppedBitmap.cs +++ b/src/Avalonia.Base/Media/Imaging/CroppedBitmap.cs @@ -48,8 +48,6 @@ namespace Avalonia.Media.Imaging 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 cbdf3c3c1e..b51093b40c 100644 --- a/src/Avalonia.Base/StyledElement.cs +++ b/src/Avalonia.Base/StyledElement.cs @@ -67,8 +67,7 @@ namespace Avalonia 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 8695918c18..5052840013 100644 --- a/src/Avalonia.Base/StyledProperty.cs +++ b/src/Avalonia.Base/StyledProperty.cs @@ -56,9 +56,14 @@ namespace Avalonia /// /// 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/Calendar/Calendar.cs b/src/Avalonia.Controls/Calendar/Calendar.cs index 3300292857..10aadfa759 100644 --- a/src/Avalonia.Controls/Calendar/Calendar.cs +++ b/src/Avalonia.Controls/Calendar/Calendar.cs @@ -232,14 +232,9 @@ namespace Avalonia.Controls 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 @@ namespace Avalonia.Controls } 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 @@ namespace Avalonia.Controls if (IsValidSelectionMode(e.NewValue!)) { _displayDateIsChanging = true; - SelectedDate = null; + SetCurrentValue(SelectedDateProperty, null); _displayDateIsChanging = false; SelectedDates.Clear(); } @@ -497,11 +492,8 @@ namespace Avalonia.Controls || 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 @@ namespace Avalonia.Controls /// 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 @@ namespace Avalonia.Controls } } - 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 @@ namespace Avalonia.Controls /// 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 @@ namespace Avalonia.Controls 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 @@ namespace Avalonia.Controls /// 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 @@ namespace Avalonia.Controls if (selectedDateMin.HasValue && DateTime.Compare(selectedDateMin.Value, newValue.Value) < 0) { - DisplayDateStart = selectedDateMin.Value; + SetCurrentValue(DisplayDateStartProperty, selectedDateMin.Value); return; } @@ -839,14 +825,14 @@ namespace Avalonia.Controls // 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 @@ namespace Avalonia.Controls 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 @@ namespace Avalonia.Controls /// 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 @@ namespace Avalonia.Controls if (selectedDateMax.HasValue && DateTime.Compare(selectedDateMax.Value, newValue.Value) > 0) { - DisplayDateEnd = selectedDateMax.Value; + SetCurrentValue(DisplayDateEndProperty, selectedDateMax.Value); return; } @@ -950,7 +933,7 @@ namespace Avalonia.Controls // DisplayDateEnd = DisplayDateStart if (DateTime.Compare(newValue.Value, DisplayDateRangeStart) < 0) { - DisplayDateEnd = DisplayDateStart; + SetCurrentValue(DisplayDateEndProperty, DisplayDateStart); return; } @@ -958,7 +941,7 @@ namespace Avalonia.Controls // DisplayDate = DisplayDateEnd if (DateTimeHelper.CompareYearMonth(newValue.Value, DisplayDateInternal) < 0) { - DisplayDate = newValue.Value; + SetCurrentValue(DisplayDateProperty, newValue.Value); } } UpdateMonths(); @@ -1284,7 +1267,7 @@ namespace Avalonia.Controls { LastSelectedDate = d.Value; } - DisplayDate = d.Value; + SetCurrentValue(DisplayDateProperty, d.Value); } } else @@ -1332,7 +1315,7 @@ namespace Avalonia.Controls { LastSelectedDate = d.Value; } - DisplayDate = d.Value; + SetCurrentValue(DisplayDateProperty, d.Value); } } else @@ -1719,7 +1702,7 @@ namespace Avalonia.Controls if (ctrl) { SelectedMonth = DisplayDateInternal; - DisplayMode = CalendarMode.Year; + SetCurrentValue(DisplayModeProperty, CalendarMode.Year); } else { @@ -1733,7 +1716,7 @@ namespace Avalonia.Controls if (ctrl) { SelectedYear = SelectedMonth; - DisplayMode = CalendarMode.Decade; + SetCurrentValue(DisplayModeProperty, CalendarMode.Decade); } else { @@ -1770,8 +1753,8 @@ namespace Avalonia.Controls { if (ctrl) { - DisplayDate = SelectedMonth; - DisplayMode = CalendarMode.Month; + SetCurrentValue(DisplayDateProperty, SelectedMonth); + SetCurrentValue(DisplayModeProperty, CalendarMode.Month); } else { @@ -1785,7 +1768,7 @@ namespace Avalonia.Controls if (ctrl) { SelectedMonth = SelectedYear; - DisplayMode = CalendarMode.Year; + SetCurrentValue(DisplayModeProperty, CalendarMode.Year); } else { @@ -1850,14 +1833,14 @@ namespace Avalonia.Controls { 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 @@ namespace Avalonia.Controls /// 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 3d436b4485..2e3f1f96ce 100644 --- a/src/Avalonia.Controls/Calendar/CalendarItem.cs +++ b/src/Avalonia.Controls/Calendar/CalendarItem.cs @@ -41,7 +41,6 @@ namespace Avalonia.Controls.Primitives private Button? _headerButton; private Button? _nextButton; private Button? _previousButton; - private ITemplate? _dayTitleTemplate; private DateTime _currentMonth; private bool _isMouseLeftButtonDown; @@ -61,17 +60,15 @@ namespace Avalonia.Controls.Primitives 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 @@ namespace Avalonia.Controls.Primitives 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 6c2356b411..5ff04b1a99 100644 --- a/src/Avalonia.Controls/CalendarDatePicker/CalendarDatePicker.Properties.cs +++ b/src/Avalonia.Controls/CalendarDatePicker/CalendarDatePicker.Properties.cs @@ -11,29 +11,22 @@ namespace Avalonia.Controls /// /// 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 @@ namespace Avalonia.Controls /// /// 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. @@ -88,11 +79,8 @@ namespace Avalonia.Controls /// /// 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 +129,8 @@ namespace Avalonia.Controls /// public DateTime DisplayDate { - get => _displayDate; - set => SetAndRaise(DisplayDateProperty, ref _displayDate, value); + get => GetValue(DisplayDateProperty); + set => SetValue(DisplayDateProperty, value); } /// @@ -151,8 +139,8 @@ namespace Avalonia.Controls /// 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 +149,8 @@ namespace Avalonia.Controls /// 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 +176,8 @@ namespace Avalonia.Controls /// public bool IsDropDownOpen { - get => _isDropDownOpen; - set => SetAndRaise(IsDropDownOpenProperty, ref _isDropDownOpen, value); + get => GetValue(IsDropDownOpenProperty); + set => SetValue(IsDropDownOpenProperty, value); } /// @@ -264,8 +252,8 @@ namespace Avalonia.Controls /// 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 869bdeabea..3f5d355b71 100644 --- a/src/Avalonia.Controls/CalendarDatePicker/CalendarDatePicker.cs +++ b/src/Avalonia.Controls/CalendarDatePicker/CalendarDatePicker.cs @@ -45,12 +45,7 @@ namespace Avalonia.Controls 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 +87,9 @@ namespace Avalonia.Controls /// public CalendarDatePicker() { - FirstDayOfWeek = DateTimeHelper.GetCurrentDateFormat().FirstDayOfWeek; + SetCurrentValue(FirstDayOfWeekProperty, DateTimeHelper.GetCurrentDateFormat().FirstDayOfWeek); _defaultText = string.Empty; - DisplayDate = DateTime.Today; + SetCurrentValue(DisplayDateProperty, DateTime.Today); } /// @@ -257,7 +252,7 @@ namespace Avalonia.Controls Threading.Dispatcher.UIThread.InvokeAsync(() => { _settingSelectedDate = true; - Text = DateTimeToString(day); + SetCurrentValue(TextProperty, DateTimeToString(day)); _settingSelectedDate = false; OnDateSelected(addedDate, removedDate); }); @@ -268,7 +263,7 @@ namespace Avalonia.Controls // 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 +312,7 @@ namespace Avalonia.Controls if (!_settingSelectedDate) { _settingSelectedDate = true; - SelectedDate = null; + SetCurrentValue(SelectedDateProperty, null); _settingSelectedDate = false; } } @@ -400,7 +395,7 @@ namespace Avalonia.Controls 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 +473,7 @@ namespace Avalonia.Controls { if (SelectedDate.HasValue) { - Text = DateTimeToString(SelectedDate.Value); + SetCurrentValue(TextProperty, DateTimeToString(SelectedDate.Value)); } else if (string.IsNullOrEmpty(_textBox.Text)) { @@ -491,7 +486,7 @@ namespace Avalonia.Controls if (date != null) { string? s = DateTimeToString((DateTime)date); - Text = s; + SetCurrentValue(TextProperty, s); } } } @@ -547,7 +542,7 @@ namespace Avalonia.Controls private void Calendar_DayButtonMouseUp(object? sender, PointerReleasedEventArgs e) { Focus(); - IsDropDownOpen = false; + SetCurrentValue(IsDropDownOpenProperty, false); } private void Calendar_DisplayDateChanged(object? sender, CalendarDateChangedEventArgs e) @@ -564,13 +559,13 @@ namespace Avalonia.Controls 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 +573,7 @@ namespace Avalonia.Controls { if (e.AddedItems.Count > 0) { - SelectedDate = (DateTime?)e.AddedItems[0]; + SetCurrentValue(SelectedDateProperty, (DateTime?)e.AddedItems[0]); } } } @@ -600,18 +595,18 @@ namespace Avalonia.Controls && (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 +622,7 @@ namespace Avalonia.Controls if (_textBox != null) { _suspendTextChangeHandler = true; - Text = _textBox.Text; + SetCurrentValue(TextProperty, _textBox.Text); _suspendTextChangeHandler = false; } } @@ -660,7 +655,7 @@ namespace Avalonia.Controls private void PopUp_Closed(object? sender, EventArgs e) { - IsDropDownOpen = false; + SetCurrentValue(IsDropDownOpenProperty, false); if(!_isPopupClosing) { @@ -678,12 +673,12 @@ namespace Avalonia.Controls if (IsDropDownOpen) { Focus(); - IsDropDownOpen = false; + SetCurrentValue(IsDropDownOpenProperty, false); } else { SetSelectedDate(); - IsDropDownOpen = true; + SetCurrentValue(IsDropDownOpenProperty, true); _calendar!.Focus(); } } @@ -821,14 +816,14 @@ namespace Avalonia.Controls if (SelectedDate != d) { - SelectedDate = d; + SetCurrentValue(SelectedDateProperty, d); } } else { if (SelectedDate != null) { - SelectedDate = null; + SetCurrentValue(SelectedDateProperty, null); } } } @@ -838,7 +833,7 @@ namespace Avalonia.Controls if (SelectedDate != d) { - SelectedDate = d; + SetCurrentValue(SelectedDateProperty, d); } } } @@ -884,7 +879,7 @@ namespace Avalonia.Controls 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 17a6ad7a09..f6e4b32d6b 100644 --- a/src/Avalonia.Controls/ComboBox.cs +++ b/src/Avalonia.Controls/ComboBox.cs @@ -35,11 +35,8 @@ namespace Avalonia.Controls /// /// 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 @@ namespace Avalonia.Controls 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 @@ namespace Avalonia.Controls /// public bool IsDropDownOpen { - get => _isDropDownOpen; - set => SetAndRaise(IsDropDownOpenProperty, ref _isDropDownOpen, value); + get => GetValue(IsDropDownOpenProperty); + set => SetValue(IsDropDownOpenProperty, value); } /// @@ -123,10 +119,10 @@ namespace Avalonia.Controls /// /// 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 @@ namespace Avalonia.Controls 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 @@ namespace Avalonia.Controls } else { - IsDropDownOpen = !IsDropDownOpen; + SetCurrentValue(IsDropDownOpenProperty, !IsDropDownOpen); e.Handled = true; } } @@ -390,7 +386,7 @@ namespace Avalonia.Controls { 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 bb05cd1b1f..118183102a 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 @@ namespace Avalonia.Controls /// /// 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 @@ namespace Avalonia.Controls 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 @@ namespace Avalonia.Controls /// public bool DayVisible { - get => _dayVisible; - set - { - SetAndRaise(DayVisibleProperty, ref _dayVisible, value); - SetGrid(); - } + get => GetValue(DayVisibleProperty); + set => SetValue(DayVisibleProperty, value); } /// @@ -145,16 +123,24 @@ namespace Avalonia.Controls /// 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 @@ namespace Avalonia.Controls /// 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 @@ namespace Avalonia.Controls /// public string MonthFormat { - get => _monthFormat; - set => SetAndRaise(MonthFormatProperty, ref _monthFormat, value); + get => GetValue(MonthFormatProperty); + set => SetValue(MonthFormatProperty, value); } /// @@ -188,12 +182,8 @@ namespace Avalonia.Controls /// public bool MonthVisible { - get => _monthVisible; - set - { - SetAndRaise(MonthVisibleProperty, ref _monthVisible, value); - SetGrid(); - } + get => GetValue(MonthVisibleProperty); + set => SetValue(MonthVisibleProperty, value); } /// @@ -201,8 +191,8 @@ namespace Avalonia.Controls /// public string YearFormat { - get => _yearFormat; - set => SetAndRaise(YearFormatProperty, ref _yearFormat, value); + get => GetValue(YearFormatProperty); + set => SetValue(YearFormatProperty, value); } /// @@ -210,12 +200,8 @@ namespace Avalonia.Controls /// public bool YearVisible { - get => _yearVisible; - set - { - SetAndRaise(YearVisibleProperty, ref _yearVisible, value); - SetGrid(); - } + get => GetValue(YearVisibleProperty); + set => SetValue(YearVisibleProperty, value); } /// @@ -223,14 +209,8 @@ namespace Avalonia.Controls /// 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 @@ namespace Avalonia.Controls } } + 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 @@ namespace Avalonia.Controls 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 2057480490..0ae743f30a 100644 --- a/src/Avalonia.Controls/DateTimePickers/DatePickerPresenter.cs +++ b/src/Avalonia.Controls/DateTimePickers/DatePickerPresenter.cs @@ -35,65 +35,72 @@ namespace Avalonia.Controls /// /// 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 @@ namespace Avalonia.Controls 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 @@ namespace Avalonia.Controls 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 @@ namespace Avalonia.Controls /// 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 @@ namespace Avalonia.Controls /// public string DayFormat { - get => _dayFormat; - set => SetAndRaise(DayFormatProperty, ref _dayFormat, value); + get => GetValue(DayFormatProperty); + set => SetValue(DayFormatProperty, value); } /// @@ -166,11 +174,8 @@ namespace Avalonia.Controls /// public bool DayVisible { - get => _dayVisible; - set - { - SetAndRaise(DayVisibleProperty, ref _dayVisible, value); - } + get => GetValue(DayVisibleProperty); + set => SetValue(DayVisibleProperty, value); } /// @@ -178,16 +183,8 @@ namespace Avalonia.Controls /// 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 @@ namespace Avalonia.Controls /// 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 @@ namespace Avalonia.Controls /// public string MonthFormat { - get => _monthFormat; - set => SetAndRaise(MonthFormatProperty, ref _monthFormat, value); + get => GetValue(MonthFormatProperty); + set => SetValue(MonthFormatProperty, value); } /// @@ -221,11 +210,8 @@ namespace Avalonia.Controls /// public bool MonthVisible { - get => _monthVisible; - set - { - SetAndRaise(MonthVisibleProperty, ref _monthVisible, value); - } + get => GetValue(MonthVisibleProperty); + set => SetValue(MonthVisibleProperty, value); } /// @@ -233,8 +219,8 @@ namespace Avalonia.Controls /// public string YearFormat { - get => _yearFormat; - set => SetAndRaise(YearFormatProperty, ref _yearFormat, value); + get => GetValue(YearFormatProperty); + set => SetValue(YearFormatProperty, value); } /// @@ -242,11 +228,8 @@ namespace Avalonia.Controls /// 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 @@ namespace Avalonia.Controls 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 @@ namespace Avalonia.Controls } break; case Key.Enter: - Date = _syncDate; + SetCurrentValue(DateProperty, _syncDate); OnConfirmed(); e.Handled = true; break; @@ -381,13 +378,13 @@ namespace Avalonia.Controls _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 @@ namespace Avalonia.Controls 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 a7a6881fe5..2f49a44b8c 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 @@ namespace Avalonia.Controls /// /// 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 @@ namespace Avalonia.Controls 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 @@ namespace Avalonia.Controls /// 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 @@ namespace Avalonia.Controls /// 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 @@ namespace Avalonia.Controls /// 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 @@ namespace Avalonia.Controls } } + 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 @@ namespace Avalonia.Controls 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 d6599c9f18..ba06e1b5e6 100644 --- a/src/Avalonia.Controls/DateTimePickers/TimePickerPresenter.cs +++ b/src/Avalonia.Controls/DateTimePickers/TimePickerPresenter.cs @@ -30,28 +30,29 @@ namespace Avalonia.Controls /// /// 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 @@ namespace Avalonia.Controls 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 @@ namespace Avalonia.Controls /// 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 @@ namespace Avalonia.Controls /// 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 @@ namespace Avalonia.Controls 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 @@ namespace Avalonia.Controls 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 12a096b105..fe9f5e64a8 100644 --- a/src/Avalonia.Controls/Documents/InlineCollection.cs +++ b/src/Avalonia.Controls/Documents/InlineCollection.cs @@ -24,7 +24,7 @@ namespace Avalonia.Controls.Documents this.ForEachItem( x => - { + { x.InlineHost = InlineHost; LogicalChildren?.Add(x); Invalidate(); @@ -92,10 +92,10 @@ namespace Avalonia.Controls.Documents 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 @@ namespace Avalonia.Controls.Documents oldParent.Remove(child); } - if(newParent != null) + if (newParent != null) { newParent.Add(child); } diff --git a/src/Avalonia.Controls/Flyouts/FlyoutBase.cs b/src/Avalonia.Controls/Flyouts/FlyoutBase.cs index 9d4abec549..36f8371702 100644 --- a/src/Avalonia.Controls/Flyouts/FlyoutBase.cs +++ b/src/Avalonia.Controls/Flyouts/FlyoutBase.cs @@ -35,17 +35,14 @@ namespace Avalonia.Controls.Primitives /// /// 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 @@ namespace Avalonia.Controls.Primitives 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 @@ namespace Avalonia.Controls.Primitives /// public FlyoutShowMode ShowMode { - get => _showMode; - set => SetAndRaise(ShowModeProperty, ref _showMode, value); + get => GetValue(ShowModeProperty); + set => SetValue(ShowModeProperty, value); } /// @@ -117,8 +112,8 @@ namespace Avalonia.Controls.Primitives /// 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 @@ namespace Avalonia.Controls.Primitives { 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 5c8a6e0a5b..487d816204 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 @@ namespace Avalonia.Controls /// /// 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 @@ namespace Avalonia.Controls [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/NativeMenu.cs b/src/Avalonia.Controls/NativeMenu.cs index 5ff4148e5a..7b03c607b6 100644 --- a/src/Avalonia.Controls/NativeMenu.cs +++ b/src/Avalonia.Controls/NativeMenu.cs @@ -79,12 +79,12 @@ namespace Avalonia.Controls } 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 32fa574ee6..b7ce928b4b 100644 --- a/src/Avalonia.Controls/NativeMenuItem.cs +++ b/src/Avalonia.Controls/NativeMenuItem.cs @@ -4,36 +4,14 @@ using Avalonia.Input; 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,71 +38,66 @@ namespace Avalonia.Controls 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 = @@ -139,18 +112,18 @@ namespace Avalonia.Controls 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; @@ -196,8 +169,20 @@ namespace Avalonia.Controls 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; + } + } } - + public enum NativeMenuItemToggleType { None, diff --git a/src/Avalonia.Controls/NativeMenuItemBase.cs b/src/Avalonia.Controls/NativeMenuItemBase.cs index 4946d16f01..70cb2b806e 100644 --- a/src/Avalonia.Controls/NativeMenuItemBase.cs +++ b/src/Avalonia.Controls/NativeMenuItemBase.cs @@ -12,12 +12,12 @@ namespace Avalonia.Controls } 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 663bd3358a..705d40380e 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 @@ namespace Avalonia.Controls.Notifications /// 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 ac4f699313..e676ec0759 100644 --- a/src/Avalonia.Controls/NumericUpDown/NumericUpDown.cs +++ b/src/Avalonia.Controls/NumericUpDown/NumericUpDown.cs @@ -43,16 +43,14 @@ namespace Avalonia.Controls /// /// 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,9 +85,8 @@ namespace Avalonia.Controls /// /// 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. @@ -101,9 +98,8 @@ namespace Avalonia.Controls /// /// 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. @@ -134,13 +130,9 @@ namespace Avalonia.Controls 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 +176,8 @@ namespace Avalonia.Controls /// public bool ClipValueToMinMax { - get { return _clipValueToMinMax; } - set { SetAndRaise(ClipValueToMinMaxProperty, ref _clipValueToMinMax, value); } + get => GetValue(ClipValueToMinMaxProperty); + set => SetValue(ClipValueToMinMaxProperty, value); } /// @@ -193,8 +185,8 @@ namespace Avalonia.Controls /// public NumberFormatInfo? NumberFormat { - get { return _numberFormat; } - set { SetAndRaise(NumberFormatProperty, ref _numberFormat, value); } + get => GetValue(NumberFormatProperty); + set => SetValue(NumberFormatProperty, value); } /// @@ -249,8 +241,8 @@ namespace Avalonia.Controls /// public NumberStyles ParsingNumberStyle { - get { return _parsingNumberStyle; } - set { SetAndRaise(ParsingNumberStyleProperty, ref _parsingNumberStyle, value); } + get => GetValue(ParsingNumberStyleProperty); + set => SetValue(ParsingNumberStyleProperty, value); } /// @@ -269,8 +261,8 @@ namespace Avalonia.Controls /// public IValueConverter? TextConverter { - get { return _textConverter; } - set { SetAndRaise(TextConverterProperty, ref _textConverter, value); } + get => GetValue(TextConverterProperty); + set => SetValue(TextConverterProperty, value); } /// @@ -475,7 +467,7 @@ namespace Avalonia.Controls } if (ClipValueToMinMax && Value.HasValue) { - Value = MathUtilities.Clamp(Value.Value, Minimum, Maximum); + SetCurrentValue(ValueProperty, MathUtilities.Clamp(Value.Value, Minimum, Maximum)); } } @@ -492,7 +484,7 @@ namespace Avalonia.Controls } if (ClipValueToMinMax && Value.HasValue) { - Value = MathUtilities.Clamp(Value.Value, Minimum, Maximum); + SetCurrentValue(ValueProperty, MathUtilities.Clamp(Value.Value, Minimum, Maximum)); } } @@ -676,7 +668,7 @@ namespace Avalonia.Controls result = Minimum; } - Value = MathUtilities.Clamp(result, Minimum, Maximum); + SetCurrentValue(ValueProperty, MathUtilities.Clamp(result, Minimum, Maximum)); } /// @@ -695,7 +687,7 @@ namespace Avalonia.Controls result = Maximum; } - Value = MathUtilities.Clamp(result, Minimum, Maximum); + SetCurrentValue(ValueProperty, MathUtilities.Clamp(result, Minimum, Maximum)); } /// @@ -862,7 +854,7 @@ namespace Avalonia.Controls _internalValueSet = true; try { - Value = value; + SetCurrentValue(ValueProperty, value); } finally { @@ -907,7 +899,7 @@ namespace Avalonia.Controls _isTextChangedFromUI = true; if (TextBox != null) { - Text = TextBox.Text; + SetCurrentValue(TextProperty, TextBox.Text); } } finally @@ -1026,7 +1018,7 @@ namespace Avalonia.Controls var newText = ConvertValueToText(); if (!Equals(Text, newText)) { - Text = newText; + SetCurrentValue(TextProperty, newText); } } diff --git a/src/Avalonia.Controls/Presenters/ContentPresenter.cs b/src/Avalonia.Controls/Presenters/ContentPresenter.cs index be61bb18a1..329a0fa6ab 100644 --- a/src/Avalonia.Controls/Presenters/ContentPresenter.cs +++ b/src/Avalonia.Controls/Presenters/ContentPresenter.cs @@ -156,16 +156,13 @@ namespace Avalonia.Controls.Presenters /// /// 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 @@ namespace Avalonia.Controls.Presenters /// 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 0a762c438d..a0020a0b6e 100644 --- a/src/Avalonia.Controls/Presenters/ItemsPresenter.cs +++ b/src/Avalonia.Controls/Presenters/ItemsPresenter.cs @@ -166,7 +166,7 @@ namespace Avalonia.Controls.Presenters } 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 9d443d9289..0c6c434713 100644 --- a/src/Avalonia.Controls/Primitives/Popup.cs +++ b/src/Avalonia.Controls/Primitives/Popup.cs @@ -2,7 +2,6 @@ using System; 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 @@ namespace Avalonia.Controls.Primitives /// /// 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 @@ namespace Avalonia.Controls.Primitives 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 @@ namespace Avalonia.Controls.Primitives 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 @@ namespace Avalonia.Controls.Primitives /// public bool IsOpen { - get { return _isOpen; } - set { SetAndRaise(IsOpenProperty, ref _isOpen, value); } + get => GetValue(IsOpenProperty); + set => SetValue(IsOpenProperty, value); } /// @@ -301,8 +292,8 @@ namespace Avalonia.Controls.Primitives /// public IInputElement? OverlayInputPassThroughElement { - get => _overlayInputPassThroughElement; - set => SetAndRaise(OverlayInputPassThroughElementProperty, ref _overlayInputPassThroughElement, value); + get => GetValue(OverlayInputPassThroughElementProperty); + set => SetValue(OverlayInputPassThroughElementProperty, value); } /// @@ -486,7 +477,7 @@ namespace Avalonia.Controls.Primitives using (BeginIgnoringIsOpen()) { - IsOpen = true; + SetCurrentValue(IsOpenProperty, true); } Opened?.Invoke(this, EventArgs.Empty); @@ -704,7 +695,7 @@ namespace Avalonia.Controls.Primitives { using (BeginIgnoringIsOpen()) { - IsOpen = false; + SetCurrentValue(IsOpenProperty, false); } return; @@ -717,7 +708,7 @@ namespace Avalonia.Controls.Primitives 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 8253342782..e1cf25d89f 100644 --- a/src/Avalonia.Controls/Primitives/TemplatedControl.cs +++ b/src/Avalonia.Controls/Primitives/TemplatedControl.cs @@ -275,7 +275,7 @@ namespace Avalonia.Controls.Primitives { foreach (var child in this.GetTemplateChildren()) { - child.SetValue(TemplatedParentProperty, null); + child.TemplatedParent = null; ((ISetLogicalParent)child).SetParent(null); } @@ -377,7 +377,7 @@ namespace Avalonia.Controls.Primitives /// 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 158c5d875b..dfaf7bbc45 100644 --- a/src/Avalonia.Controls/Primitives/ToggleButton.cs +++ b/src/Avalonia.Controls/Primitives/ToggleButton.cs @@ -15,12 +15,8 @@ namespace Avalonia.Controls.Primitives /// /// 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 @@ namespace Avalonia.Controls.Primitives nameof(IsCheckedChanged), RoutingStrategies.Bubble); - private bool? _isChecked = false; - static ToggleButton() { } @@ -119,12 +113,8 @@ namespace Avalonia.Controls.Primitives /// public bool? IsChecked { - get => _isChecked; - set - { - SetAndRaise(IsCheckedProperty, ref _isChecked, value); - UpdatePseudoClasses(IsChecked); - } + get => GetValue(IsCheckedProperty); + set => SetValue(IsCheckedProperty, value); } /// @@ -147,28 +137,31 @@ namespace Avalonia.Controls.Primitives /// 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 @@ namespace Avalonia.Controls.Primitives { 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 87772aced7..d4528fdb1c 100644 --- a/src/Avalonia.Controls/RadioButton.cs +++ b/src/Avalonia.Controls/RadioButton.cs @@ -98,31 +98,22 @@ namespace Avalonia.Controls } } - 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 @@ namespace Avalonia.Controls 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/TreeViewItem.cs b/src/Avalonia.Controls/TreeViewItem.cs index e9abfef673..3ac157f727 100644 --- a/src/Avalonia.Controls/TreeViewItem.cs +++ b/src/Avalonia.Controls/TreeViewItem.cs @@ -104,12 +104,12 @@ namespace Avalonia.Controls 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 ba1b599421..f9593f1c1b 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.Interactivity; using Avalonia.Layout; using Avalonia.Media; using Avalonia.Platform; +using Avalonia.Reactive; using Avalonia.Styling; namespace Avalonia.Controls @@ -149,11 +148,8 @@ namespace Avalonia.Controls /// /// 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 @@ namespace Avalonia.Controls 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 @@ namespace Avalonia.Controls { get => GetValue(ExtendClientAreaTitleBarHeightHintProperty); set => SetValue(ExtendClientAreaTitleBarHeightHintProperty, value); - } + } /// /// Gets if the ClientArea is Extended into the Window Decorations. @@ -314,7 +309,7 @@ namespace Avalonia.Controls { get => _isExtendedIntoWindowDecorations; private set => SetAndRaise(IsExtendedIntoWindowDecorationsProperty, ref _isExtendedIntoWindowDecorations, value); - } + } /// /// Gets the WindowDecorationMargin. @@ -324,7 +319,7 @@ namespace Avalonia.Controls { get => _windowDecorationMargin; private set => SetAndRaise(WindowDecorationMarginProperty, ref _windowDecorationMargin, value); - } + } /// /// Gets the window margin that is hidden off the screen area. @@ -397,8 +392,8 @@ namespace Avalonia.Controls /// public WindowStartupLocation WindowStartupLocation { - get { return _windowStartupLocation; } - set { SetAndRaise(WindowStartupLocationProperty, ref _windowStartupLocation, value); } + get => GetValue(WindowStartupLocationProperty); + set => SetValue(WindowStartupLocationProperty, value); } /// @@ -488,7 +483,7 @@ namespace Avalonia.Controls CloseInternal(); return false; } - + return true; } @@ -614,7 +609,7 @@ namespace Avalonia.Controls if (_shown != isVisible) { - if(!_shown) + if (!_shown) { Show(); } @@ -657,7 +652,7 @@ namespace Avalonia.Controls throw new InvalidOperationException("Cannot re-show a closed window."); } } - + private void EnsureParentStateBeforeShow(Window owner) { if (owner.PlatformImpl == null) @@ -819,7 +814,7 @@ namespace Avalonia.Controls { bool isEnabled = true; - foreach (var (_, isDialog) in _children) + foreach (var (_, isDialog) in _children) { if (isDialog) { @@ -856,7 +851,7 @@ namespace Avalonia.Controls { Window? firstDialogChild = null; - foreach (var (child, isDialog) in _children) + foreach (var (child, isDialog) in _children) { if (isDialog) { @@ -880,7 +875,7 @@ namespace Avalonia.Controls 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 @@ namespace Avalonia.Controls 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 26e11f0d4a..814a9b5960 100644 --- a/src/Avalonia.Controls/WindowBase.cs +++ b/src/Avalonia.Controls/WindowBase.cs @@ -27,10 +27,7 @@ namespace Avalonia.Controls /// 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 c9189a886d..f765871ee8 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 @@ namespace Avalonia.Diagnostics.Controls 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 @@ namespace Avalonia.Diagnostics.Controls (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 ba321db144..cfb1b508d9 100644 --- a/src/Markup/Avalonia.Markup/Data/TemplateBinding.cs +++ b/src/Markup/Avalonia.Markup/Data/TemplateBinding.cs @@ -104,9 +104,7 @@ namespace Avalonia.Data 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 738469bc6f..7528815510 100644 --- a/tests/Avalonia.Base.UnitTests/Styling/SelectorTests_Template.cs +++ b/tests/Avalonia.Base.UnitTests/Styling/SelectorTests_Template.cs @@ -35,7 +35,7 @@ namespace Avalonia.Base.UnitTests.Styling .Template() .OfType(); - border.SetValue(StyledElement.TemplatedParentProperty, null); + border.TemplatedParent = null; Assert.Equal(SelectorMatchResult.NeverThisInstance, selector.Match(border).Result); } @@ -124,10 +124,10 @@ namespace Avalonia.Base.UnitTests.Styling { 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 3aaf62f0bf..7b5aa83b46 100644 --- a/tests/Avalonia.Controls.UnitTests/ItemsControlTests.cs +++ b/tests/Avalonia.Controls.UnitTests/ItemsControlTests.cs @@ -131,7 +131,7 @@ namespace Avalonia.Controls.UnitTests 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 d3737de45b..9042e84fa1 100644 --- a/tests/Avalonia.Controls.UnitTests/Presenters/ContentPresenterTests_InTemplate.cs +++ b/tests/Avalonia.Controls.UnitTests/Presenters/ContentPresenterTests_InTemplate.cs @@ -26,7 +26,7 @@ namespace Avalonia.Controls.UnitTests.Presenters 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 71f803fab7..573ce5834d 100644 --- a/tests/Avalonia.Controls.UnitTests/Presenters/ItemsPresenterTests.cs +++ b/tests/Avalonia.Controls.UnitTests/Presenters/ItemsPresenterTests.cs @@ -22,7 +22,7 @@ namespace Avalonia.Controls.UnitTests.Presenters 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 8789d79742..33593a0631 100644 --- a/tests/Avalonia.Controls.UnitTests/Templates/TemplateExtensionsTests.cs +++ b/tests/Avalonia.Controls.UnitTests/Templates/TemplateExtensionsTests.cs @@ -18,17 +18,17 @@ namespace Avalonia.Controls.Templates.UnitTests 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 @@ namespace Avalonia.Controls.Templates.UnitTests Assert.Equal(new[] { "border1", "inner", "border4" }, result); } } -} \ No newline at end of file +}