NativeMenuItem.cs 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. using System;
  2. using System.Windows.Input;
  3. using Avalonia.Input;
  4. using Avalonia.Utilities;
  5. namespace Avalonia.Controls
  6. {
  7. public class NativeMenuItem : NativeMenuItemBase
  8. {
  9. private string _header;
  10. private KeyGesture _gesture;
  11. private bool _enabled = true;
  12. private NativeMenu _menu;
  13. static NativeMenuItem()
  14. {
  15. MenuProperty.Changed.Subscribe(args =>
  16. {
  17. var item = (NativeMenuItem)args.Sender;
  18. var value = (NativeMenu)args.NewValue;
  19. if (value.Parent != null && value.Parent != item)
  20. throw new InvalidOperationException("NativeMenu already has a parent");
  21. value.Parent = item;
  22. });
  23. }
  24. class CanExecuteChangedSubscriber : IWeakSubscriber<EventArgs>
  25. {
  26. private readonly NativeMenuItem _parent;
  27. public CanExecuteChangedSubscriber(NativeMenuItem parent)
  28. {
  29. _parent = parent;
  30. }
  31. public void OnEvent(object sender, EventArgs e)
  32. {
  33. _parent.CanExecuteChanged();
  34. }
  35. }
  36. private readonly CanExecuteChangedSubscriber _canExecuteChangedSubscriber;
  37. public NativeMenuItem()
  38. {
  39. _canExecuteChangedSubscriber = new CanExecuteChangedSubscriber(this);
  40. }
  41. public NativeMenuItem(string header) : this()
  42. {
  43. Header = header;
  44. }
  45. public static readonly DirectProperty<NativeMenuItem, NativeMenu> MenuProperty =
  46. AvaloniaProperty.RegisterDirect<NativeMenuItem, NativeMenu>(nameof(Menu), o => o._menu,
  47. (o, v) =>
  48. {
  49. if (v.Parent != null && v.Parent != o)
  50. throw new InvalidOperationException("NativeMenu already has a parent");
  51. o._menu = v;
  52. });
  53. public NativeMenu Menu
  54. {
  55. get => _menu;
  56. set
  57. {
  58. if (value.Parent != null && value.Parent != this)
  59. throw new InvalidOperationException("NativeMenu already has a parent");
  60. SetAndRaise(MenuProperty, ref _menu, value);
  61. }
  62. }
  63. public static readonly DirectProperty<NativeMenuItem, string> HeaderProperty =
  64. AvaloniaProperty.RegisterDirect<NativeMenuItem, string>(nameof(Header), o => o._header, (o, v) => o._header = v);
  65. public string Header
  66. {
  67. get => GetValue(HeaderProperty);
  68. set => SetValue(HeaderProperty, value);
  69. }
  70. public static readonly DirectProperty<NativeMenuItem, KeyGesture> GestureProperty =
  71. AvaloniaProperty.RegisterDirect<NativeMenuItem, KeyGesture>(nameof(Gesture), o => o._gesture, (o, v) => o._gesture = v);
  72. public KeyGesture Gesture
  73. {
  74. get => GetValue(GestureProperty);
  75. set => SetValue(GestureProperty, value);
  76. }
  77. private ICommand _command;
  78. public static readonly DirectProperty<NativeMenuItem, ICommand> CommandProperty =
  79. AvaloniaProperty.RegisterDirect<NativeMenuItem, ICommand>(nameof(Command),
  80. o => o._command, (o, v) =>
  81. {
  82. if (o._command != null)
  83. WeakSubscriptionManager.Unsubscribe(o._command,
  84. nameof(ICommand.CanExecuteChanged), o._canExecuteChangedSubscriber);
  85. o._command = v;
  86. if (o._command != null)
  87. WeakSubscriptionManager.Subscribe(o._command,
  88. nameof(ICommand.CanExecuteChanged), o._canExecuteChangedSubscriber);
  89. o.CanExecuteChanged();
  90. });
  91. /// <summary>
  92. /// Defines the <see cref="CommandParameter"/> property.
  93. /// </summary>
  94. public static readonly StyledProperty<object> CommandParameterProperty =
  95. Button.CommandParameterProperty.AddOwner<MenuItem>();
  96. public static readonly DirectProperty<NativeMenuItem, bool> EnabledProperty =
  97. AvaloniaProperty.RegisterDirect<NativeMenuItem, bool>(nameof(Enabled), o => o._enabled,
  98. (o, v) => o._enabled = v, true);
  99. public bool Enabled
  100. {
  101. get => GetValue(EnabledProperty);
  102. set => SetValue(EnabledProperty, value);
  103. }
  104. void CanExecuteChanged()
  105. {
  106. Enabled = _command?.CanExecute(null) ?? true;
  107. }
  108. public bool HasClickHandlers => Clicked != null;
  109. public ICommand Command
  110. {
  111. get => GetValue(CommandProperty);
  112. set => SetValue(CommandProperty, value);
  113. }
  114. /// <summary>
  115. /// Gets or sets the parameter to pass to the <see cref="Command"/> property of a
  116. /// <see cref="NativeMenuItem"/>.
  117. /// </summary>
  118. public object CommandParameter
  119. {
  120. get { return GetValue(CommandParameterProperty); }
  121. set { SetValue(CommandParameterProperty, value); }
  122. }
  123. public event EventHandler Clicked;
  124. public void RaiseClick()
  125. {
  126. Clicked?.Invoke(this, new EventArgs());
  127. if (Command?.CanExecute(CommandParameter) == true)
  128. {
  129. Command.Execute(CommandParameter);
  130. }
  131. }
  132. }
  133. }