A cross-platform UI framework for .NET
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

185 lines
6.1 KiB

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<EventArgs>
{
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<NativeMenu?> MenuProperty =
AvaloniaProperty.Register<NativeMenuItem, NativeMenu?>(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<IBitmap?> IconProperty =
AvaloniaProperty.Register<NativeMenuItem, IBitmap?>(nameof(Icon));
public IBitmap? Icon
{
get => GetValue(IconProperty);
set => SetValue(IconProperty, value);
}
public static readonly StyledProperty<string?> HeaderProperty =
AvaloniaProperty.Register<NativeMenuItem, string?>(nameof(Header));
public string? Header
{
get => GetValue(HeaderProperty);
set => SetValue(HeaderProperty, value);
}
public static readonly StyledProperty<KeyGesture?> GestureProperty =
AvaloniaProperty.Register<NativeMenuItem, KeyGesture?>(nameof(Gesture));
public KeyGesture? Gesture
{
get => GetValue(GestureProperty);
set => SetValue(GestureProperty, value);
}
public static readonly StyledProperty<bool> IsCheckedProperty =
AvaloniaProperty.Register<NativeMenuItem, bool>(nameof(IsChecked));
public bool IsChecked
{
get => GetValue(IsCheckedProperty);
set => SetValue(IsCheckedProperty, value);
}
public static readonly StyledProperty<NativeMenuItemToggleType> ToggleTypeProperty =
AvaloniaProperty.Register<NativeMenuItem, NativeMenuItemToggleType>(nameof(ToggleType));
public NativeMenuItemToggleType ToggleType
{
get => GetValue(ToggleTypeProperty);
set => SetValue(ToggleTypeProperty, value);
}
public static readonly StyledProperty<ICommand?> CommandProperty =
Button.CommandProperty.AddOwner<NativeMenuItem>(new(enableDataValidation: true));
/// <summary>
/// Defines the <see cref="CommandParameter"/> property.
/// </summary>
public static readonly StyledProperty<object?> CommandParameterProperty =
Button.CommandParameterProperty.AddOwner<NativeMenuItem>();
public static readonly StyledProperty<bool> IsEnabledProperty =
AvaloniaProperty.Register<NativeMenuItem, bool>(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);
}
/// <summary>
/// Gets or sets the parameter to pass to the <see cref="Command"/> property of a
/// <see cref="NativeMenuItem"/>.
/// </summary>
public object? CommandParameter
{
get { return GetValue(CommandParameterProperty); }
set { SetValue(CommandParameterProperty, value); }
}
/// <summary>
/// Occurs when a <see cref="NativeMenuItem"/> is clicked.
/// </summary>
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
}
}