using System; using System.Windows.Input; using Avalonia.Input; using Avalonia.Media.Imaging; using Avalonia.Metadata; using Avalonia.Utilities; namespace Avalonia.Controls { public class NativeMenuItem : NativeMenuItemBase, INativeMenuItemExporterEventsImplBridge { private readonly CanExecuteChangedSubscriber _canExecuteChangedSubscriber; class CanExecuteChangedSubscriber : IWeakEventSubscriber { private readonly NativeMenuItem _parent; public CanExecuteChangedSubscriber(NativeMenuItem parent) { _parent = parent; } public void OnEvent(object? sender, WeakEvent ev, EventArgs e) { _parent.CanExecuteChanged(); } } public NativeMenuItem() { _canExecuteChangedSubscriber = new CanExecuteChangedSubscriber(this); } public NativeMenuItem(string header) : this() { Header = header; } public static readonly StyledProperty MenuProperty = AvaloniaProperty.Register(nameof(Menu), coerce: CoerceMenu); [Content] public NativeMenu? Menu { get => GetValue(MenuProperty); set => SetValue(MenuProperty, value); } 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 => GetValue(IconProperty); set => SetValue(IconProperty, value); } public static readonly StyledProperty HeaderProperty = AvaloniaProperty.Register(nameof(Header)); public string? Header { get => GetValue(HeaderProperty); set => SetValue(HeaderProperty, value); } public static readonly StyledProperty GestureProperty = AvaloniaProperty.Register(nameof(Gesture)); public KeyGesture? Gesture { get => GetValue(GestureProperty); set => SetValue(GestureProperty, value); } public static readonly StyledProperty IsCheckedProperty = AvaloniaProperty.Register(nameof(IsChecked)); public bool IsChecked { get => GetValue(IsCheckedProperty); set => SetValue(IsCheckedProperty, value); } public static readonly StyledProperty ToggleTypeProperty = AvaloniaProperty.Register(nameof(ToggleType)); public NativeMenuItemToggleType ToggleType { get => GetValue(ToggleTypeProperty); set => SetValue(ToggleTypeProperty, value); } public static readonly StyledProperty CommandProperty = Button.CommandProperty.AddOwner(new(enableDataValidation: true)); /// /// Defines the property. /// public static readonly StyledProperty CommandParameterProperty = Button.CommandParameterProperty.AddOwner(); public static readonly StyledProperty IsEnabledProperty = AvaloniaProperty.Register(nameof(IsEnabled), true); public bool IsEnabled { get => GetValue(IsEnabledProperty); set => SetValue(IsEnabledProperty, value); } void CanExecuteChanged() { SetCurrentValue(IsEnabledProperty, Command?.CanExecute(CommandParameter) ?? true); } public bool HasClickHandlers => Click != null; public ICommand? Command { get => GetValue(CommandProperty); set => SetValue(CommandProperty, value); } /// /// Gets or sets the parameter to pass to the property of a /// . /// public object? CommandParameter { get { return GetValue(CommandParameterProperty); } set { SetValue(CommandParameterProperty, value); } } /// /// Occurs when a is clicked. /// public event EventHandler? Click; void INativeMenuItemExporterEventsImplBridge.RaiseClicked() { Click?.Invoke(this, new EventArgs()); if (Command?.CanExecute(CommandParameter) == true) { Command.Execute(CommandParameter); } } protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) { base.OnPropertyChanged(change); if (change.Property == MenuProperty && change.NewValue is NativeMenu newMenu) { if (newMenu.Parent != null && newMenu.Parent != this) throw new InvalidOperationException("NativeMenu already has a parent"); newMenu.Parent = this; } else if (change.Property == CommandProperty) { if (change.OldValue is ICommand oldCommand) WeakEvents.CommandCanExecuteChanged.Unsubscribe(oldCommand, _canExecuteChangedSubscriber); if (change.NewValue is ICommand newCommand) WeakEvents.CommandCanExecuteChanged.Subscribe(newCommand, _canExecuteChangedSubscriber); CanExecuteChanged(); } } } public enum NativeMenuItemToggleType { None, CheckBox, Radio } }