SideMenuItem.cs 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. using System;
  2. using System.Linq;
  3. using System.Windows;
  4. using System.Windows.Data;
  5. using System.Windows.Input;
  6. using HandyControl.Data;
  7. using HandyControl.Tools.Extension;
  8. namespace HandyControl.Controls;
  9. public class SideMenuItem : HeaderedSimpleItemsControl, ISelectable, ICommandSource
  10. {
  11. private bool _isMouseLeftButtonDown;
  12. public static readonly DependencyProperty IconProperty = DependencyProperty.Register(
  13. nameof(Icon), typeof(object), typeof(SideMenuItem), new PropertyMetadata(default(object)));
  14. public object Icon
  15. {
  16. get => GetValue(IconProperty);
  17. set => SetValue(IconProperty, value);
  18. }
  19. public SideMenuItem()
  20. {
  21. SetBinding(ExpandModeProperty, new Binding(SideMenu.ExpandModeProperty.Name)
  22. {
  23. RelativeSource = new RelativeSource(RelativeSourceMode.FindAncestor, typeof(SideMenu), 1)
  24. });
  25. }
  26. internal static readonly DependencyProperty ExpandModeProperty =
  27. SideMenu.ExpandModeProperty.AddOwner(typeof(SideMenuItem), new PropertyMetadata(default(ExpandMode)));
  28. internal ExpandMode ExpandMode
  29. {
  30. get => (ExpandMode) GetValue(ExpandModeProperty);
  31. set => SetValue(ExpandModeProperty, value);
  32. }
  33. protected override void Refresh()
  34. {
  35. if (ItemsHost == null) return;
  36. ItemsHost.Children.Clear();
  37. foreach (var item in Items)
  38. {
  39. DependencyObject container;
  40. if (IsItemItsOwnContainerOverride(item))
  41. {
  42. container = item as DependencyObject;
  43. }
  44. else
  45. {
  46. container = GetContainerForItemOverride();
  47. PrepareContainerForItemOverride(container, item);
  48. }
  49. if (container is FrameworkElement element)
  50. {
  51. element.Style = ItemContainerStyle;
  52. ItemsHost.Children.Add(element);
  53. }
  54. }
  55. if (IsLoaded)
  56. {
  57. SwitchPanelArea(ExpandMode == ExpandMode.ShowAll || IsSelected);
  58. }
  59. }
  60. protected virtual void OnSelected(RoutedEventArgs e)
  61. {
  62. RaiseEvent(e);
  63. switch (Command)
  64. {
  65. case null:
  66. return;
  67. case RoutedCommand command:
  68. command.Execute(CommandParameter, CommandTarget);
  69. break;
  70. default:
  71. Command.Execute(CommandParameter);
  72. break;
  73. }
  74. }
  75. public static readonly RoutedEvent SelectedEvent =
  76. EventManager.RegisterRoutedEvent("Selected", RoutingStrategy.Bubble,
  77. typeof(RoutedEventHandler), typeof(SideMenuItem));
  78. public event RoutedEventHandler Selected
  79. {
  80. add => AddHandler(SelectedEvent, value);
  81. remove => RemoveHandler(SelectedEvent, value);
  82. }
  83. public static readonly DependencyProperty IsSelectedProperty = DependencyProperty.Register(
  84. nameof(IsSelected), typeof(bool), typeof(SideMenuItem), new PropertyMetadata(ValueBoxes.FalseBox));
  85. public bool IsSelected
  86. {
  87. get => (bool) GetValue(IsSelectedProperty);
  88. set => SetValue(IsSelectedProperty, ValueBoxes.BooleanBox(value));
  89. }
  90. public static readonly DependencyProperty RoleProperty = DependencyProperty.Register(
  91. nameof(Role), typeof(SideMenuItemRole), typeof(SideMenuItem), new PropertyMetadata(default(SideMenuItemRole)));
  92. public SideMenuItemRole Role
  93. {
  94. get => (SideMenuItemRole) GetValue(RoleProperty);
  95. internal set => SetValue(RoleProperty, value);
  96. }
  97. protected override DependencyObject GetContainerForItemOverride() => new SideMenuItem();
  98. protected override bool IsItemItsOwnContainerOverride(object item) => item is SideMenuItem;
  99. protected override void OnMouseLeave(MouseEventArgs e)
  100. {
  101. base.OnMouseLeave(e);
  102. _isMouseLeftButtonDown = false;
  103. }
  104. protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
  105. {
  106. base.OnMouseLeftButtonDown(e);
  107. _isMouseLeftButtonDown = true;
  108. }
  109. protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e)
  110. {
  111. base.OnMouseLeftButtonUp(e);
  112. if (_isMouseLeftButtonDown)
  113. {
  114. IsSelected = true;
  115. OnSelected(new RoutedEventArgs(SelectedEvent, this));
  116. _isMouseLeftButtonDown = false;
  117. }
  118. }
  119. internal void SelectDefaultItem()
  120. {
  121. if (Role == SideMenuItemRole.Header && ItemsHost.Children.Count > 0)
  122. {
  123. var item = ItemsHost.Children.OfType<SideMenuItem>().FirstOrDefault();
  124. if (item is { IsSelected: false })
  125. {
  126. item.OnSelected(new RoutedEventArgs(SelectedEvent, item));
  127. }
  128. }
  129. }
  130. internal void SwitchPanelArea(bool isShow)
  131. {
  132. if (ItemsHost == null) return;
  133. if (Role == SideMenuItemRole.Header)
  134. {
  135. ItemsHost.Show(isShow);
  136. }
  137. }
  138. public static readonly DependencyProperty CommandProperty = DependencyProperty.Register(
  139. nameof(Command), typeof(ICommand), typeof(SideMenuItem), new PropertyMetadata(default(ICommand), OnCommandChanged));
  140. private static void OnCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
  141. {
  142. var ctl = (SideMenuItem) d;
  143. if (e.OldValue is ICommand oldCommand)
  144. {
  145. oldCommand.CanExecuteChanged -= ctl.CanExecuteChanged;
  146. }
  147. if (e.NewValue is ICommand newCommand)
  148. {
  149. newCommand.CanExecuteChanged += ctl.CanExecuteChanged;
  150. }
  151. }
  152. public ICommand Command
  153. {
  154. get => (ICommand) GetValue(CommandProperty);
  155. set => SetValue(CommandProperty, value);
  156. }
  157. public static readonly DependencyProperty CommandParameterProperty = DependencyProperty.Register(
  158. nameof(CommandParameter), typeof(object), typeof(SideMenuItem), new PropertyMetadata(default(object)));
  159. public object CommandParameter
  160. {
  161. get => GetValue(CommandParameterProperty);
  162. set => SetValue(CommandParameterProperty, value);
  163. }
  164. public static readonly DependencyProperty CommandTargetProperty = DependencyProperty.Register(
  165. nameof(CommandTarget), typeof(IInputElement), typeof(SideMenuItem), new PropertyMetadata(default(IInputElement)));
  166. public IInputElement CommandTarget
  167. {
  168. get => (IInputElement) GetValue(CommandTargetProperty);
  169. set => SetValue(CommandTargetProperty, value);
  170. }
  171. private void CanExecuteChanged(object sender, EventArgs e)
  172. {
  173. if (Command == null) return;
  174. IsEnabled = Command is RoutedCommand command
  175. ? command.CanExecute(CommandParameter, CommandTarget)
  176. : Command.CanExecute(CommandParameter);
  177. }
  178. }