RateItem.cs 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. using System.Windows;
  2. using System.Windows.Controls;
  3. using System.Windows.Input;
  4. using System.Windows.Media;
  5. using HandyControl.Data;
  6. using HandyControl.Tools.Extension;
  7. namespace HandyControl.Controls;
  8. [TemplatePart(Name = ElementIcon, Type = typeof(FrameworkElement))]
  9. public class RateItem : Control
  10. {
  11. private const string ElementIcon = "PART_Icon";
  12. public static readonly DependencyProperty AllowClearProperty =
  13. Rate.AllowClearProperty.AddOwner(typeof(RateItem));
  14. public static readonly DependencyProperty AllowHalfProperty =
  15. Rate.AllowHalfProperty.AddOwner(typeof(RateItem), new PropertyMetadata(OnAllowHalfChanged));
  16. public static readonly DependencyProperty IconProperty = Rate.IconProperty.AddOwner(typeof(RateItem));
  17. public static readonly DependencyProperty IsReadOnlyProperty = Rate.IsReadOnlyProperty.AddOwner(typeof(RateItem));
  18. internal static readonly DependencyProperty IsSelectedProperty = DependencyProperty.Register(
  19. nameof(IsSelected), typeof(bool), typeof(RateItem),
  20. new PropertyMetadata(ValueBoxes.FalseBox, OnIsSelectedChanged));
  21. public static readonly RoutedEvent SelectedChangedEvent =
  22. EventManager.RegisterRoutedEvent("SelectedChanged", RoutingStrategy.Bubble,
  23. typeof(RoutedEventHandler), typeof(RateItem));
  24. public static readonly RoutedEvent ValueChangedEvent =
  25. EventManager.RegisterRoutedEvent("ValueChanged", RoutingStrategy.Bubble,
  26. typeof(RoutedEventHandler), typeof(RateItem));
  27. private FrameworkElement _icon;
  28. private bool _isHalf;
  29. private bool _isLoaded;
  30. private bool _isMouseLeftButtonDown;
  31. private bool _isSentValue;
  32. public RateItem()
  33. {
  34. Loaded += (s, e) =>
  35. {
  36. if (_isLoaded) return;
  37. _isLoaded = true;
  38. OnApplyTemplate();
  39. };
  40. }
  41. public bool AllowClear
  42. {
  43. get => (bool) GetValue(AllowClearProperty);
  44. set => SetValue(AllowClearProperty, ValueBoxes.BooleanBox(value));
  45. }
  46. public bool AllowHalf
  47. {
  48. get => (bool) GetValue(AllowHalfProperty);
  49. set => SetValue(AllowHalfProperty, ValueBoxes.BooleanBox(value));
  50. }
  51. public Geometry Icon
  52. {
  53. get => (Geometry) GetValue(IconProperty);
  54. set => SetValue(IconProperty, value);
  55. }
  56. internal bool IsSelected
  57. {
  58. get => (bool) GetValue(IsSelectedProperty);
  59. set => SetValue(IsSelectedProperty, ValueBoxes.BooleanBox(value));
  60. }
  61. public bool IsReadOnly
  62. {
  63. get => (bool) GetValue(IsReadOnlyProperty);
  64. set => SetValue(IsReadOnlyProperty, ValueBoxes.BooleanBox(value));
  65. }
  66. internal bool IsHalf
  67. {
  68. get => _isHalf;
  69. set
  70. {
  71. if (_isHalf == value) return;
  72. _isHalf = value;
  73. if (_icon == null) return;
  74. _icon.Width = value ? Width / 2 : Width;
  75. }
  76. }
  77. internal int Index { get; set; }
  78. private static void OnAllowHalfChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
  79. {
  80. var ctl = (RateItem) d;
  81. ctl.HandleMouseMoveEvent((bool) e.NewValue);
  82. }
  83. private static void OnIsSelectedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
  84. {
  85. var ctl = (RateItem) d;
  86. ctl._icon?.Show((bool) e.NewValue);
  87. }
  88. public event RoutedEventHandler SelectedChanged
  89. {
  90. add => AddHandler(SelectedChangedEvent, value);
  91. remove => RemoveHandler(SelectedChangedEvent, value);
  92. }
  93. public event RoutedEventHandler ValueChanged
  94. {
  95. add => AddHandler(ValueChangedEvent, value);
  96. remove => RemoveHandler(ValueChangedEvent, value);
  97. }
  98. private void HandleMouseMoveEvent(bool handle)
  99. {
  100. if (handle)
  101. {
  102. MouseMove += RateItem_MouseMove;
  103. }
  104. else
  105. {
  106. MouseMove -= RateItem_MouseMove;
  107. }
  108. }
  109. private void RateItem_MouseMove(object sender, MouseEventArgs e)
  110. {
  111. if (IsReadOnly) return;
  112. if (!AllowHalf) return;
  113. var p = e.GetPosition(this);
  114. IsHalf = p.X < Width / 2;
  115. }
  116. public override void OnApplyTemplate()
  117. {
  118. base.OnApplyTemplate();
  119. _icon = GetTemplateChild(ElementIcon) as FrameworkElement;
  120. if (_isLoaded)
  121. {
  122. if (_icon == null) return;
  123. _icon.Show(IsSelected);
  124. _icon.Width = IsHalf ? Width / 2 : Width;
  125. }
  126. }
  127. protected override void OnMouseEnter(MouseEventArgs e)
  128. {
  129. base.OnMouseEnter(e);
  130. if (IsReadOnly) return;
  131. _isSentValue = false;
  132. IsSelected = true;
  133. RaiseEvent(new RoutedEventArgs(SelectedChangedEvent) { Source = this });
  134. }
  135. protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
  136. {
  137. base.OnMouseLeftButtonDown(e);
  138. if (IsReadOnly) return;
  139. _isMouseLeftButtonDown = true;
  140. }
  141. protected override void OnMouseLeave(MouseEventArgs e)
  142. {
  143. base.OnMouseLeave(e);
  144. if (IsReadOnly) return;
  145. _isMouseLeftButtonDown = false;
  146. }
  147. protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e)
  148. {
  149. base.OnMouseLeftButtonUp(e);
  150. if (IsReadOnly) return;
  151. if (_isMouseLeftButtonDown)
  152. {
  153. if (Index == 1 && AllowClear)
  154. {
  155. if (IsSelected)
  156. {
  157. if (!_isSentValue)
  158. {
  159. RaiseEvent(new RoutedEventArgs(ValueChangedEvent) { Source = this });
  160. _isMouseLeftButtonDown = false;
  161. _isSentValue = true;
  162. return;
  163. }
  164. _isSentValue = false;
  165. IsSelected = false;
  166. IsHalf = false;
  167. }
  168. else
  169. {
  170. IsSelected = true;
  171. if (AllowHalf)
  172. {
  173. var p = e.GetPosition(this);
  174. IsHalf = p.X < Width / 2;
  175. }
  176. }
  177. }
  178. RaiseEvent(new RoutedEventArgs(ValueChangedEvent) { Source = this });
  179. _isMouseLeftButtonDown = false;
  180. }
  181. }
  182. }