diff --git a/src/Avalonia.Controls/Button.cs b/src/Avalonia.Controls/Button.cs
index 1ec6f8dabc..f48d7a7cc1 100644
--- a/src/Avalonia.Controls/Button.cs
+++ b/src/Avalonia.Controls/Button.cs
@@ -1,11 +1,9 @@
using System;
-using System.Diagnostics;
using System.Linq;
using System.Windows.Input;
using Avalonia.Automation.Peers;
using Avalonia.Controls.Metadata;
using Avalonia.Controls.Primitives;
-using Avalonia.Controls.Templates;
using Avalonia.Data;
using Avalonia.Input;
using Avalonia.Interactivity;
@@ -48,9 +46,8 @@ namespace Avalonia.Controls
///
/// Defines the property.
///
- public static readonly DirectProperty CommandProperty =
- AvaloniaProperty.RegisterDirect(nameof(Command),
- button => button.Command, (button, command) => button.Command = command, enableDataValidation: true);
+ public static readonly StyledProperty CommandProperty =
+ AvaloniaProperty.Register(nameof(Command), enableDataValidation: true);
///
/// Defines the property.
@@ -85,8 +82,8 @@ namespace Avalonia.Controls
///
/// Defines the property.
///
- public static readonly StyledProperty IsPressedProperty =
- AvaloniaProperty.Register(nameof(IsPressed));
+ public static readonly DirectProperty IsPressedProperty =
+ AvaloniaProperty.RegisterDirect(nameof(IsPressed), b => b.IsPressed);
///
/// Defines the property
@@ -94,10 +91,10 @@ namespace Avalonia.Controls
public static readonly StyledProperty FlyoutProperty =
AvaloniaProperty.Register(nameof(Flyout));
- private ICommand? _command;
private bool _commandCanExecute = true;
private KeyGesture? _hotkey;
private bool _isFlyoutOpen = false;
+ private bool _isPressed = false;
///
/// Initializes static members of the class.
@@ -138,8 +135,8 @@ namespace Avalonia.Controls
///
public ICommand? Command
{
- get => _command;
- set => SetAndRaise(CommandProperty, ref _command, value);
+ get => GetValue(CommandProperty);
+ set => SetValue(CommandProperty, value);
}
///
@@ -185,8 +182,8 @@ namespace Avalonia.Controls
///
public bool IsPressed
{
- get => GetValue(IsPressedProperty);
- private set => SetValue(IsPressedProperty, value);
+ get => _isPressed;
+ private set => SetAndRaise(IsPressedProperty, ref _isPressed, value);
}
///
@@ -248,7 +245,7 @@ namespace Avalonia.Controls
{
if (_hotkey != null) // Control attached again, set Hotkey to create a hotkey manager for this control
{
- HotKey = _hotkey;
+ SetCurrentValue(HotKeyProperty, _hotkey);
}
base.OnAttachedToLogicalTree(e);
@@ -267,7 +264,7 @@ namespace Avalonia.Controls
if (HotKey != null)
{
_hotkey = HotKey;
- HotKey = null;
+ SetCurrentValue(HotKeyProperty, null);
}
base.OnDetachedFromLogicalTree(e);
@@ -291,17 +288,17 @@ namespace Avalonia.Controls
break;
case Key.Space:
- {
- if (ClickMode == ClickMode.Press)
{
- OnClick();
+ if (ClickMode == ClickMode.Press)
+ {
+ OnClick();
+ }
+
+ IsPressed = true;
+ e.Handled = true;
+ break;
}
- IsPressed = true;
- e.Handled = true;
- break;
- }
-
case Key.Escape when Flyout != null:
// If Flyout doesn't have focusable content, close the flyout here
CloseFlyout();
@@ -592,7 +589,7 @@ namespace Avalonia.Controls
{
flyout.Opened -= Flyout_Opened;
flyout.Closed -= Flyout_Closed;
- }
+ }
}
///
@@ -671,7 +668,7 @@ namespace Avalonia.Controls
void ICommandSource.CanExecuteChanged(object sender, EventArgs e) => this.CanExecuteChanged(sender, e);
void IClickableControl.RaiseClick() => OnClick();
-
+
///
/// Event handler for when the button's flyout is opened.
///
diff --git a/src/Avalonia.Controls/CalendarDatePicker/CalendarDatePicker.Properties.cs b/src/Avalonia.Controls/CalendarDatePicker/CalendarDatePicker.Properties.cs
index 5ff04b1a99..1454b4ab6c 100644
--- a/src/Avalonia.Controls/CalendarDatePicker/CalendarDatePicker.Properties.cs
+++ b/src/Avalonia.Controls/CalendarDatePicker/CalendarDatePicker.Properties.cs
@@ -50,11 +50,9 @@ namespace Avalonia.Controls
///
/// Defines the property.
///
- public static readonly DirectProperty SelectedDateProperty =
- AvaloniaProperty.RegisterDirect(
+ public static readonly StyledProperty SelectedDateProperty =
+ AvaloniaProperty.Register(
nameof(SelectedDate),
- o => o.SelectedDate,
- (o, v) => o.SelectedDate = v,
enableDataValidation: true,
defaultBindingMode:BindingMode.TwoWay);
@@ -211,8 +209,8 @@ namespace Avalonia.Controls
///
public DateTime? SelectedDate
{
- get => _selectedDate;
- set => SetAndRaise(SelectedDateProperty, ref _selectedDate, value);
+ get => GetValue(SelectedDateProperty);
+ set => SetValue(SelectedDateProperty, value);
}
///
diff --git a/src/Avalonia.Controls/CalendarDatePicker/CalendarDatePicker.cs b/src/Avalonia.Controls/CalendarDatePicker/CalendarDatePicker.cs
index 3f5d355b71..c091d07632 100644
--- a/src/Avalonia.Controls/CalendarDatePicker/CalendarDatePicker.cs
+++ b/src/Avalonia.Controls/CalendarDatePicker/CalendarDatePicker.cs
@@ -45,7 +45,6 @@ namespace Avalonia.Controls
private DateTime? _onOpenSelectedDate;
private bool _settingSelectedDate;
- private DateTime? _selectedDate;
private bool _suspendTextChangeHandler;
private bool _isPopupClosing;
private bool _ignoreButtonClick;
diff --git a/src/Avalonia.Controls/MenuItem.cs b/src/Avalonia.Controls/MenuItem.cs
index 1670e496b4..03e3444d71 100644
--- a/src/Avalonia.Controls/MenuItem.cs
+++ b/src/Avalonia.Controls/MenuItem.cs
@@ -27,11 +27,8 @@ namespace Avalonia.Controls
///
/// Defines the property.
///
- public static readonly DirectProperty CommandProperty =
- Button.CommandProperty.AddOwner(
- menuItem => menuItem.Command,
- (menuItem, command) => menuItem.Command = command,
- enableDataValidation: true);
+ public static readonly StyledProperty CommandProperty =
+ Button.CommandProperty.AddOwner(new(enableDataValidation: true));
///
/// Defines the property.
@@ -113,7 +110,6 @@ namespace Avalonia.Controls
private static readonly ITemplate DefaultPanel =
new FuncTemplate(() => new StackPanel());
- private ICommand? _command;
private bool _commandCanExecute = true;
private bool _commandBindingError;
private Popup? _popup;
@@ -217,8 +213,8 @@ namespace Avalonia.Controls
///
public ICommand? Command
{
- get { return _command; }
- set { SetAndRaise(CommandProperty, ref _command, value); }
+ get => GetValue(CommandProperty);
+ set => SetValue(CommandProperty, value);
}
///
@@ -337,7 +333,7 @@ namespace Avalonia.Controls
///
/// This has the same effect as setting to true.
///
- public void Open() => IsSubMenuOpen = true;
+ public void Open() => SetCurrentValue(IsSubMenuOpenProperty, true);
///
/// Closes the submenu.
@@ -345,7 +341,7 @@ namespace Avalonia.Controls
///
/// This has the same effect as setting to false.
///
- public void Close() => IsSubMenuOpen = false;
+ public void Close() => SetCurrentValue(IsSubMenuOpenProperty, false);
///
void IMenuItem.RaiseClick() => RaiseEvent(new RoutedEventArgs(ClickEvent));
@@ -369,7 +365,7 @@ namespace Avalonia.Controls
{
if (_hotkey != null) // Control attached again, set Hotkey to create a hotkey manager for this control
{
- HotKey = _hotkey;
+ SetCurrentValue(HotKeyProperty, _hotkey);
}
base.OnAttachedToLogicalTree(e);
@@ -397,7 +393,7 @@ namespace Avalonia.Controls
if (HotKey != null)
{
_hotkey = HotKey;
- HotKey = null;
+ SetCurrentValue(HotKeyProperty, null);
}
base.OnDetachedFromLogicalTree(e);
@@ -663,7 +659,7 @@ namespace Avalonia.Controls
}
RaiseEvent(new RoutedEventArgs(SubmenuOpenedEvent));
- IsSelected = true;
+ SetCurrentValue(IsSelectedProperty, true);
PseudoClasses.Add(":open");
}
else
diff --git a/src/Avalonia.Controls/NativeMenuItem.cs b/src/Avalonia.Controls/NativeMenuItem.cs
index b7ce928b4b..9b5f756887 100644
--- a/src/Avalonia.Controls/NativeMenuItem.cs
+++ b/src/Avalonia.Controls/NativeMenuItem.cs
@@ -9,7 +9,6 @@ namespace Avalonia.Controls
{
public class NativeMenuItem : NativeMenuItemBase, INativeMenuItemExporterEventsImplBridge
{
- private ICommand? _command;
private readonly CanExecuteChangedSubscriber _canExecuteChangedSubscriber;
class CanExecuteChangedSubscriber : IWeakEventSubscriber
@@ -100,11 +99,8 @@ namespace Avalonia.Controls
set => SetValue(ToggleTypeProperty, value);
}
- public static readonly DirectProperty CommandProperty =
- Button.CommandProperty.AddOwner(
- menuItem => menuItem.Command,
- (menuItem, command) => menuItem.Command = command,
- enableDataValidation: true);
+ public static readonly StyledProperty CommandProperty =
+ Button.CommandProperty.AddOwner(new(enableDataValidation: true));
///
/// Defines the property.
@@ -130,19 +126,8 @@ namespace Avalonia.Controls
public ICommand? Command
{
- get => _command;
- set
- {
- if (_command != null)
- WeakEvents.CommandCanExecuteChanged.Unsubscribe(_command, _canExecuteChangedSubscriber);
-
- SetAndRaise(CommandProperty, ref _command, value);
-
- if (_command != null)
- WeakEvents.CommandCanExecuteChanged.Subscribe(_command, _canExecuteChangedSubscriber);
-
- CanExecuteChanged();
- }
+ get => GetValue(CommandProperty);
+ set => SetValue(CommandProperty, value);
}
///
@@ -180,6 +165,14 @@ namespace Avalonia.Controls
throw new InvalidOperationException("NativeMenu already has a parent");
newMenu.Parent = this;
}
+ else if (change.Property == CommandProperty)
+ {
+ if (change.OldValue is ICommand oldCommand)
+ WeakEvents.CommandCanExecuteChanged.Unsubscribe(oldCommand, _canExecuteChangedSubscriber);
+ if (change.NewValue is ICommand newCommand)
+ WeakEvents.CommandCanExecuteChanged.Subscribe(newCommand, _canExecuteChangedSubscriber);
+ CanExecuteChanged();
+ }
}
}
diff --git a/src/Avalonia.Controls/NumericUpDown/NumericUpDown.cs b/src/Avalonia.Controls/NumericUpDown/NumericUpDown.cs
index e676ec0759..885a8af5d1 100644
--- a/src/Avalonia.Controls/NumericUpDown/NumericUpDown.cs
+++ b/src/Avalonia.Controls/NumericUpDown/NumericUpDown.cs
@@ -91,8 +91,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),
defaultBindingMode: BindingMode.TwoWay, enableDataValidation: true);
///
@@ -104,9 +104,9 @@ namespace Avalonia.Controls
///
/// Defines the property.
///
- public static readonly DirectProperty ValueProperty =
- AvaloniaProperty.RegisterDirect(nameof(Value), updown => updown.Value,
- (updown, v) => updown.Value = v, defaultBindingMode: BindingMode.TwoWay, enableDataValidation: true);
+ public static readonly StyledProperty ValueProperty =
+ AvaloniaProperty.Register(nameof(Value), coerce: (s,v) => ((NumericUpDown)s).OnCoerceValue(v),
+ defaultBindingMode: BindingMode.TwoWay, enableDataValidation: true);
///
/// Defines the property.
@@ -128,8 +128,6 @@ namespace Avalonia.Controls
private IDisposable? _textBoxTextChangedSubscription;
- private decimal? _value;
- private string? _text;
private bool _internalValueSet;
private bool _isSyncingTextAndValueProperties;
private bool _isTextChangedFromUI;
@@ -250,8 +248,8 @@ namespace Avalonia.Controls
///
public string? Text
{
- get { return _text; }
- set { SetAndRaise(TextProperty, ref _text, value); }
+ get => GetValue(TextProperty);
+ set => SetValue(TextProperty, value);
}
///
@@ -270,12 +268,8 @@ namespace Avalonia.Controls
///
public decimal? Value
{
- get { return _value; }
- set
- {
- value = OnCoerceValue(value);
- SetAndRaise(ValueProperty, ref _value, value);
- }
+ get => GetValue(ValueProperty);
+ set => SetValue(ValueProperty, value);
}
///
@@ -500,7 +494,7 @@ namespace Avalonia.Controls
SyncTextAndValueProperties(true, Text);
}
}
-
+
///
/// Called when the property value changed.
///
@@ -667,7 +661,7 @@ namespace Avalonia.Controls
{
result = Minimum;
}
-
+
SetCurrentValue(ValueProperty, MathUtilities.Clamp(result, Minimum, Maximum));
}
@@ -677,7 +671,7 @@ namespace Avalonia.Controls
private void OnDecrement()
{
decimal result;
-
+
if (Value.HasValue)
{
result = Value.Value - Increment;
@@ -686,7 +680,7 @@ namespace Avalonia.Controls
{
result = Maximum;
}
-
+
SetCurrentValue(ValueProperty, MathUtilities.Clamp(result, Minimum, Maximum));
}
@@ -704,7 +698,7 @@ namespace Avalonia.Controls
{
validDirections = ValidSpinDirections.Increase | ValidSpinDirections.Decrease;
}
-
+
if (Value < Maximum)
{
validDirections = validDirections | ValidSpinDirections.Increase;
@@ -1058,7 +1052,7 @@ namespace Avalonia.Controls
{
return null;
}
-
+
if (TextConverter != null)
{
var valueFromText = TextConverter.Convert(text, typeof(decimal?), null, CultureInfo.CurrentCulture);
diff --git a/src/Avalonia.Controls/SplitButton/SplitButton.cs b/src/Avalonia.Controls/SplitButton/SplitButton.cs
index 31a06d875a..e82fb39a66 100644
--- a/src/Avalonia.Controls/SplitButton/SplitButton.cs
+++ b/src/Avalonia.Controls/SplitButton/SplitButton.cs
@@ -42,10 +42,8 @@ namespace Avalonia.Controls
///
/// Defines the property.
///
- public static readonly DirectProperty CommandProperty =
- Button.CommandProperty.AddOwner(
- splitButton => splitButton.Command,
- (splitButton, command) => splitButton.Command = command);
+ public static readonly StyledProperty CommandProperty =
+ Button.CommandProperty.AddOwner();
///
/// Defines the property.
@@ -59,8 +57,6 @@ namespace Avalonia.Controls
public static readonly StyledProperty FlyoutProperty =
Button.FlyoutProperty.AddOwner();
- private ICommand? _Command;
-
private Button? _primaryButton = null;
private Button? _secondaryButton = null;
@@ -83,8 +79,8 @@ namespace Avalonia.Controls
///
public ICommand? Command
{
- get => _Command;
- set => SetAndRaise(CommandProperty, ref _Command, value);
+ get => GetValue(CommandProperty);
+ set => SetValue(CommandProperty, value);
}
///
diff --git a/src/Avalonia.Controls/TrayIcon.cs b/src/Avalonia.Controls/TrayIcon.cs
index 5713846b35..73bcb84c69 100644
--- a/src/Avalonia.Controls/TrayIcon.cs
+++ b/src/Avalonia.Controls/TrayIcon.cs
@@ -13,13 +13,10 @@ namespace Avalonia.Controls
public sealed class TrayIcons : AvaloniaList
{
}
-
-
public class TrayIcon : AvaloniaObject, INativeMenuExporterProvider, IDisposable
{
private readonly ITrayIconImpl? _impl;
- private ICommand? _command;
private TrayIcon(ITrayIconImpl? impl)
{
@@ -85,11 +82,8 @@ namespace Avalonia.Controls
///
/// Defines the property.
///
- public static readonly DirectProperty CommandProperty =
- Button.CommandProperty.AddOwner(
- trayIcon => trayIcon.Command,
- (trayIcon, command) => trayIcon.Command = command,
- enableDataValidation: true);
+ public static readonly StyledProperty CommandProperty =
+ Button.CommandProperty.AddOwner(new(enableDataValidation: true));
///
/// Defines the property.
@@ -136,8 +130,8 @@ namespace Avalonia.Controls
///
public ICommand? Command
{
- get => _command;
- set => SetAndRaise(CommandProperty, ref _command, value);
+ get => GetValue(CommandProperty);
+ set => SetValue(CommandProperty, value);
}
///
diff --git a/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/XamlIlTests.cs b/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/XamlIlTests.cs
index be2cae8ec4..09ed78accb 100644
--- a/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/XamlIlTests.cs
+++ b/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/XamlIlTests.cs
@@ -21,17 +21,6 @@ namespace Avalonia.Markup.Xaml.UnitTests
{
public class XamlIlTests : XamlTestBase
{
- [Fact]
- public void Binding_Button_IsPressed_ShouldWork()
- {
- var parsed = (Button)AvaloniaRuntimeXamlLoader.Parse(@"
- ");
- var ctx = new XamlIlBugTestsDataContext();
- parsed.DataContext = ctx;
- parsed.SetValue(Button.IsPressedProperty, true);
- Assert.True(ctx.IsPressed);
- }
-
[Fact]
public void Transitions_Should_Be_Properly_Parsed()
{
@@ -426,7 +415,6 @@ namespace Avalonia.Markup.Xaml.UnitTests
public class XamlIlBugTestsDataContext : INotifyPropertyChanged
{
- public bool IsPressed { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)