RatingItem.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346
  1. // (c) Copyright Microsoft Corporation.
  2. // This source is subject to the Microsoft Public License (Ms-PL).
  3. // Please see http://go.microsoft.com/fwlink/?LinkID=131993] for details.
  4. // All other rights reserved.
  5. using System.Diagnostics.CodeAnalysis;
  6. using System.Globalization;
  7. using System.Windows.Automation.Peers;
  8. using System.Windows.Controls.Primitives;
  9. using System.Windows.Input;
  10. namespace System.Windows.Controls
  11. {
  12. /// <summary>
  13. /// An item used in a rating control.
  14. /// </summary>
  15. /// <QualityBand>Preview</QualityBand>
  16. [TemplateVisualState(Name = VisualStates.StateNormal, GroupName = VisualStates.GroupCommon)]
  17. [TemplateVisualState(Name = VisualStates.StateMouseOver, GroupName = VisualStates.GroupCommon)]
  18. [TemplateVisualState(Name = VisualStates.StatePressed, GroupName = VisualStates.GroupCommon)]
  19. [TemplateVisualState(Name = VisualStates.StateDisabled, GroupName = VisualStates.GroupCommon)]
  20. [TemplateVisualState(Name = VisualStates.StateReadOnly, GroupName = VisualStates.GroupCommon)]
  21. [TemplateVisualState(Name = VisualStates.StateFocused, GroupName = VisualStates.GroupFocus)]
  22. [TemplateVisualState(Name = VisualStates.StateUnfocused, GroupName = VisualStates.GroupFocus)]
  23. [TemplateVisualState(Name = StateFilled, GroupName = GroupFill)]
  24. [TemplateVisualState(Name = StateEmpty, GroupName = GroupFill)]
  25. [TemplateVisualState(Name = StatePartial, GroupName = GroupFill)]
  26. public class RatingItem : ButtonBase, IUpdateVisualState
  27. {
  28. /// <summary>
  29. /// The state in which the item is filled.
  30. /// </summary>
  31. private const string StateFilled = "Filled";
  32. /// <summary>
  33. /// The state in which the item is empty.
  34. /// </summary>
  35. private const string StateEmpty = "Empty";
  36. /// <summary>
  37. /// The group that contains fill states.
  38. /// </summary>
  39. private const string GroupFill = "FillStates";
  40. /// <summary>
  41. /// The state in which the item is partially filled.
  42. /// </summary>
  43. private const string StatePartial = "Partial";
  44. /// <summary>
  45. /// The interaction helper used to get the common states working.
  46. /// </summary>
  47. private InteractionHelper _interactionHelper;
  48. #region public double DisplayValue
  49. /// <summary>
  50. /// A value indicating whether the actual value is being set.
  51. /// </summary>
  52. private bool _settingDisplayValue;
  53. /// <summary>
  54. /// Gets the actual value.
  55. /// </summary>
  56. public double DisplayValue
  57. {
  58. get { return (double)GetValue(DisplayValueProperty); }
  59. internal set
  60. {
  61. _settingDisplayValue = true;
  62. try
  63. {
  64. SetValue(DisplayValueProperty, value);
  65. }
  66. finally
  67. {
  68. _settingDisplayValue = false;
  69. }
  70. }
  71. }
  72. /// <summary>
  73. /// Identifies the DisplayValue dependency property.
  74. /// </summary>
  75. public static readonly DependencyProperty DisplayValueProperty =
  76. DependencyProperty.Register(
  77. "DisplayValue",
  78. typeof(double),
  79. typeof(RatingItem),
  80. new PropertyMetadata(0.0, OnDisplayValueChanged));
  81. /// <summary>
  82. /// DisplayValueProperty property changed handler.
  83. /// </summary>
  84. /// <param name="d">RatingItem that changed its DisplayValue.</param>
  85. /// <param name="e">Event arguments.</param>
  86. private static void OnDisplayValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
  87. {
  88. RatingItem source = (RatingItem)d;
  89. source.OnDisplayValueChanged((double)e.OldValue, (double)e.NewValue);
  90. }
  91. /// <summary>
  92. /// DisplayValueProperty property changed handler.
  93. /// </summary>
  94. /// <param name="oldValue">The old value.</param>
  95. /// <param name="newValue">The new value.</param>
  96. private void OnDisplayValueChanged(double oldValue, double newValue)
  97. {
  98. if (!_settingDisplayValue)
  99. {
  100. _settingDisplayValue = true;
  101. this.DisplayValue = oldValue;
  102. throw new InvalidOperationException(string.Format(CultureInfo.CurrentUICulture, Muchinfo.WPF.Controls.Properties.Resources.InvalidAttemptToChangeReadOnlyProperty, "DisplayValue"));
  103. }
  104. else
  105. {
  106. if (newValue <= 0.0)
  107. {
  108. VisualStates.GoToState(this, true, StateEmpty);
  109. }
  110. else if (newValue >= 1.0)
  111. {
  112. VisualStates.GoToState(this, true, StateFilled);
  113. }
  114. else
  115. {
  116. VisualStates.GoToState(this, true, StatePartial);
  117. }
  118. }
  119. }
  120. #endregion public double DisplayValue
  121. #region public bool IsReadOnly
  122. /// <summary>
  123. /// A value indicating whether the read only value is being set.
  124. /// </summary>
  125. private bool _settingIsReadOnly;
  126. /// <summary>
  127. /// Gets a value indicating whether the control is read-only.
  128. /// </summary>
  129. public bool IsReadOnly
  130. {
  131. get { return (bool)GetValue(IsReadOnlyProperty); }
  132. internal set
  133. {
  134. _settingIsReadOnly = true;
  135. try
  136. {
  137. SetValue(IsReadOnlyProperty, value);
  138. }
  139. finally
  140. {
  141. _settingIsReadOnly = false;
  142. }
  143. }
  144. }
  145. /// <summary>
  146. /// Identifies the IsReadOnly dependency property.
  147. /// </summary>
  148. public static readonly DependencyProperty IsReadOnlyProperty =
  149. DependencyProperty.Register(
  150. "IsReadOnly",
  151. typeof(bool),
  152. typeof(RatingItem),
  153. new PropertyMetadata(false, OnIsReadOnlyChanged));
  154. /// <summary>
  155. /// IsReadOnlyProperty property changed handler.
  156. /// </summary>
  157. /// <param name="d">RatingItem that changed its IsReadOnly.</param>
  158. /// <param name="e">Event arguments.</param>
  159. private static void OnIsReadOnlyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
  160. {
  161. RatingItem source = (RatingItem)d;
  162. bool oldValue = (bool)e.OldValue;
  163. bool newValue = (bool)e.NewValue;
  164. source.OnIsReadOnlyChanged(oldValue, newValue);
  165. }
  166. /// <summary>
  167. /// IsReadOnlyProperty property changed handler.
  168. /// </summary>
  169. /// <param name="oldValue">Old value.</param>
  170. /// <param name="newValue">New value.</param>
  171. protected virtual void OnIsReadOnlyChanged(bool oldValue, bool newValue)
  172. {
  173. if (!_settingIsReadOnly)
  174. {
  175. _settingIsReadOnly = true;
  176. this.IsReadOnly = oldValue;
  177. throw new InvalidOperationException(string.Format(CultureInfo.CurrentUICulture, Muchinfo.WPF.Controls.Properties.Resources.InvalidAttemptToChangeReadOnlyProperty, "IsReadOnly"));
  178. }
  179. else
  180. {
  181. _interactionHelper.OnIsReadOnlyChanged(newValue);
  182. }
  183. }
  184. #endregion public bool IsReadOnly
  185. /// <summary>
  186. /// Gets or sets the parent rating of this rating item.
  187. /// </summary>
  188. internal Rating ParentRating { get; set; }
  189. #region public double Value
  190. /// <summary>
  191. /// Gets or sets the value property.
  192. /// </summary>
  193. [SuppressMessage("Microsoft.Naming", "CA1721:PropertyNamesShouldNotMatchGetMethods", Justification = "Value is the logical name for this property.")]
  194. internal double Value
  195. {
  196. get { return (double)GetValue(ValueProperty); }
  197. set { SetValue(ValueProperty, value); }
  198. }
  199. /// <summary>
  200. /// Identifies the Value dependency property.
  201. /// </summary>
  202. internal static readonly DependencyProperty ValueProperty =
  203. DependencyProperty.Register(
  204. "Value",
  205. typeof(double),
  206. typeof(RatingItem),
  207. new PropertyMetadata(0.0));
  208. /// <summary>
  209. /// Selects a value and raises the value selected event.
  210. /// </summary>
  211. internal void SelectValue()
  212. {
  213. if (!this.IsReadOnly)
  214. {
  215. this.Value = 1.0;
  216. OnClick();
  217. }
  218. }
  219. #endregion public double Value
  220. #if !SILVERLIGHT
  221. /// <summary>
  222. /// Initializes the static members of the ColumnDataPoint class.
  223. /// </summary>
  224. static RatingItem()
  225. {
  226. DefaultStyleKeyProperty.OverrideMetadata(typeof(RatingItem), new FrameworkPropertyMetadata(typeof(RatingItem)));
  227. }
  228. #endif
  229. /// <summary>
  230. /// Initializes a new instance of the RatingItem class.
  231. /// </summary>
  232. public RatingItem()
  233. {
  234. #if SILVERLIGHT
  235. this.DefaultStyleKey = typeof(RatingItem);
  236. #endif
  237. _interactionHelper = new InteractionHelper(this);
  238. }
  239. /// <summary>
  240. /// Provides handling for the RatingItem's MouseLeftButtonDown event.
  241. /// </summary>
  242. /// <param name="e">Event arguments.</param>
  243. protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
  244. {
  245. if (_interactionHelper.AllowMouseLeftButtonDown(e))
  246. {
  247. _interactionHelper.OnMouseLeftButtonDownBase();
  248. }
  249. base.OnMouseLeftButtonDown(e);
  250. }
  251. /// <summary>
  252. /// Provides handling for the RatingItem's MouseLeftButtonUp event.
  253. /// </summary>
  254. /// <param name="e">Event arguments.</param>
  255. protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e)
  256. {
  257. if (_interactionHelper.AllowMouseLeftButtonUp(e))
  258. {
  259. _interactionHelper.OnMouseLeftButtonUpBase();
  260. }
  261. base.OnMouseLeftButtonUp(e);
  262. }
  263. /// <summary>
  264. /// This method is invoked when the mouse enters the rating item.
  265. /// </summary>
  266. /// <param name="e">Information about the event.</param>
  267. protected override void OnMouseEnter(MouseEventArgs e)
  268. {
  269. if (_interactionHelper.AllowMouseEnter(e))
  270. {
  271. _interactionHelper.UpdateVisualStateBase(true);
  272. }
  273. base.OnMouseEnter(e);
  274. }
  275. /// <summary>
  276. /// This method is invoked when the mouse leaves the rating item.
  277. /// </summary>
  278. /// <param name="e">Information about the event.</param>
  279. protected override void OnMouseLeave(MouseEventArgs e)
  280. {
  281. if (_interactionHelper.AllowMouseLeave(e))
  282. {
  283. _interactionHelper.UpdateVisualStateBase(true);
  284. }
  285. base.OnMouseLeave(e);
  286. }
  287. /// <summary>
  288. /// Sets the value to 1.0 when clicked.
  289. /// </summary>
  290. protected override void OnClick()
  291. {
  292. base.OnClick();
  293. }
  294. /// <summary>
  295. /// Updates the visual state.
  296. /// </summary>
  297. /// <param name="useTransitions">A value indicating whether to use
  298. /// transitions.</param>
  299. void IUpdateVisualState.UpdateVisualState(bool useTransitions)
  300. {
  301. _interactionHelper.UpdateVisualStateBase(useTransitions);
  302. }
  303. /// <summary>
  304. /// Returns a AccordionItemAutomationPeer for use by the Silverlight
  305. /// automation infrastructure.
  306. /// </summary>
  307. /// <returns>A AccordionItemAutomationPeer object for the AccordionItem.</returns>
  308. protected override AutomationPeer OnCreateAutomationPeer()
  309. {
  310. return new RatingItemAutomationPeer(this);
  311. }
  312. }
  313. }