| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944 |
- // (c) Copyright Microsoft Corporation.
- // This source is subject to the Microsoft Public License (Ms-PL).
- // Please see http://go.microsoft.com/fwlink/?LinkID=131993] for details.
- // All other rights reserved.
- using System.Collections;
- using System.Collections.Generic;
- using System.Collections.Specialized;
- using System.ComponentModel;
- using System.Diagnostics.CodeAnalysis;
- using System.Linq;
- using System.Windows.Automation;
- using System.Windows.Automation.Peers;
- using System.Windows.Controls.Primitives;
- using System.Windows.Data;
- using System.Windows.Input;
- using System.Windows.Media.Animation;
- namespace System.Windows.Controls
- {
- /// <summary>
- /// A control that has a rating.
- /// </summary>
- /// <QualityBand>Preview</QualityBand>
- [TemplateVisualState(Name = VisualStates.StateNormal, GroupName = VisualStates.GroupCommon)]
- [TemplateVisualState(Name = VisualStates.StateMouseOver, GroupName = VisualStates.GroupCommon)]
- [TemplateVisualState(Name = VisualStates.StatePressed, GroupName = VisualStates.GroupCommon)]
- [TemplateVisualState(Name = VisualStates.StateDisabled, GroupName = VisualStates.GroupCommon)]
- [TemplateVisualState(Name = VisualStates.StateReadOnly, GroupName = VisualStates.GroupCommon)]
- [TemplateVisualState(Name = VisualStates.StateFocused, GroupName = VisualStates.GroupFocus)]
- [TemplateVisualState(Name = VisualStates.StateUnfocused, GroupName = VisualStates.GroupFocus)]
- [StyleTypedProperty(Property = "ItemContainerStyle", StyleTargetType = typeof(RatingItem))]
- public class Rating : ItemsControl, IUpdateVisualState
- {
- #region protected double DisplayValue
- /// <summary>
- /// Gets or sets the actual value of the Rating control.
- /// </summary>
- protected double DisplayValue
- {
- get { return (double)GetValue(DisplayValueProperty); }
- set { SetValue(DisplayValueProperty, value); }
- }
- /// <summary>
- /// Identifies the DisplayValue dependency property.
- /// </summary>
- protected static readonly DependencyProperty DisplayValueProperty =
- DependencyProperty.Register(
- "DisplayValue",
- typeof(double),
- typeof(Rating),
- new PropertyMetadata(0.0, OnDisplayValueChanged));
- /// <summary>
- /// DisplayValueProperty property changed handler.
- /// </summary>
- /// <param name="dependencyObject">Rating that changed its DisplayValue.</param>
- /// <param name="eventArgs">Event arguments.</param>
- private static void OnDisplayValueChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs eventArgs)
- {
- Rating source = (Rating)dependencyObject;
- source.OnDisplayValueChanged();
- }
- /// <summary>
- /// DisplayValueProperty property changed handler.
- /// </summary>
- private void OnDisplayValueChanged()
- {
- UpdateDisplayValues();
- }
- #endregion protected double DisplayValue
- /// <summary>
- /// Gets or sets the rating item hovered over.
- /// </summary>
- private RatingItem HoveredRatingItem { get; set; }
- /// <summary>
- /// Gets the helper that provides all of the standard
- /// interaction functionality.
- /// </summary>
- internal InteractionHelper Interaction { get; private set; }
- #if SILVERLIGHT
- /// <summary>
- /// Gets or sets the items control helper class.
- /// </summary>
- private ItemsControlHelper ItemsControlHelper { get; set; }
- #endif
- #region public int ItemCount
- /// <summary>
- /// Gets or sets the number of rating items.
- /// </summary>
- public int ItemCount
- {
- get { return (int)GetValue(ItemCountProperty); }
- set { SetValue(ItemCountProperty, value); }
- }
- /// <summary>
- /// Identifies the ItemCount dependency property.
- /// </summary>
- public static readonly DependencyProperty ItemCountProperty =
- DependencyProperty.Register(
- "ItemCount",
- typeof(int),
- typeof(Rating),
- new PropertyMetadata(0, OnItemCountChanged));
- /// <summary>
- /// ItemCountProperty property changed handler.
- /// </summary>
- /// <param name="d">Rating that changed its ItemCount.</param>
- /// <param name="e">Event arguments.</param>
- private static void OnItemCountChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
- {
- Rating source = d as Rating;
- int value = (int)e.NewValue;
- source.OnItemCountChanged(value);
- }
- /// <summary>
- /// This method is invoked when the items count property is changed.
- /// </summary>
- /// <param name="newValue">The new value.</param>
- private void OnItemCountChanged(int newValue)
- {
- if (newValue < 0)
- {
- throw new ArgumentException(Muchinfo.WPF.Controls.Properties.Resources.Rating_SetItemCount_ItemCountMustBeLargerThanOrEqualToZero);
- }
- int amountToAdd = newValue - this.Items.Count;
- if (amountToAdd > 0)
- {
- for (int cnt = 0; cnt < amountToAdd; cnt++)
- {
- this.Items.Add(new RatingItem());
- }
- }
- else if (amountToAdd < 0)
- {
- for (int cnt = 0; cnt < Math.Abs(amountToAdd); cnt++)
- {
- this.Items.RemoveAt(this.Items.Count - 1);
- }
- }
- }
- #endregion public int ItemCount
- #region public bool IsReadOnly
- /// <summary>
- /// Gets or sets a value indicating whether the Rating is read-only.
- /// </summary>
- public bool IsReadOnly
- {
- get { return (bool)GetValue(IsReadOnlyProperty); }
- set { SetValue(IsReadOnlyProperty, value); }
- }
- /// <summary>
- /// Identifies the IsReadOnly dependency property.
- /// </summary>
- public static readonly DependencyProperty IsReadOnlyProperty =
- DependencyProperty.Register(
- "IsReadOnly",
- typeof(bool),
- typeof(Rating),
- new PropertyMetadata(false, OnIsReadOnlyChanged));
- /// <summary>
- /// IsReadOnlyProperty property changed handler.
- /// </summary>
- /// <param name="d">Rating that changed its IsReadOnly.</param>
- /// <param name="e">Event arguments.</param>
- private static void OnIsReadOnlyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
- {
- Rating source = (Rating)d;
- bool oldValue = (bool)e.OldValue;
- bool newValue = (bool)e.NewValue;
- source.OnIsReadOnlyChanged(oldValue, newValue);
- }
- /// <summary>
- /// IsReadOnlyProperty property changed handler.
- /// </summary>
- /// <param name="oldValue">Old value.</param>
- /// <param name="newValue">New value.</param>
- protected virtual void OnIsReadOnlyChanged(bool oldValue, bool newValue)
- {
- Interaction.OnIsReadOnlyChanged(newValue);
- foreach (RatingItem ratingItem in GetRatingItems())
- {
- ratingItem.IsReadOnly = newValue;
- }
- UpdateHoverStates();
- }
- #endregion public bool IsReadOnly
- #if SILVERLIGHT
- #region public Style ItemContainerStyle
- /// <summary>
- /// Gets or sets the item container style.
- /// </summary>
- public Style ItemContainerStyle
- {
- get { return GetValue(ItemContainerStyleProperty) as Style; }
- set { SetValue(ItemContainerStyleProperty, value); }
- }
- /// <summary>
- /// Identifies the ItemContainerStyle dependency property.
- /// </summary>
- public static readonly DependencyProperty ItemContainerStyleProperty =
- DependencyProperty.Register(
- "ItemContainerStyle",
- typeof(Style),
- typeof(Rating),
- new PropertyMetadata(null, OnItemContainerStyleChanged));
- /// <summary>
- /// ItemContainerStyleProperty property changed handler.
- /// </summary>
- /// <param name="d">Rating that changed its ItemContainerStyle.</param>
- /// <param name="e">Event arguments.</param>
- private static void OnItemContainerStyleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
- {
- Rating source = (Rating)d;
- Style newValue = (Style)e.NewValue;
- source.OnItemContainerStyleChanged(newValue);
- }
- /// <summary>
- /// ItemContainerStyleProperty property changed handler.
- /// </summary>
- /// <param name="newValue">New value.</param>
- protected virtual void OnItemContainerStyleChanged(Style newValue)
- {
- ItemsControlHelper.UpdateItemContainerStyle(newValue);
- }
- #endregion public Style ItemContainerStyle
- #endif
- #region public RatingSelectionMode SelectionMode
- /// <summary>
- /// Gets or sets the selection mode.
- /// </summary>
- public RatingSelectionMode SelectionMode
- {
- get { return (RatingSelectionMode) GetValue(SelectionModeProperty); }
- set { SetValue(SelectionModeProperty, value); }
- }
- /// <summary>
- /// Identifies the SelectionMode dependency property.
- /// </summary>
- public static readonly DependencyProperty SelectionModeProperty =
- DependencyProperty.Register(
- "SelectionMode",
- typeof(RatingSelectionMode),
- typeof(Rating),
- new PropertyMetadata(RatingSelectionMode.Continuous, OnSelectionModeChanged));
- /// <summary>
- /// SelectionModeProperty property changed handler.
- /// </summary>
- /// <param name="d">Rating that changed its SelectionMode.</param>
- /// <param name="e">Event arguments.</param>
- private static void OnSelectionModeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
- {
- Rating source = (Rating)d;
- RatingSelectionMode oldValue = (RatingSelectionMode)e.OldValue;
- RatingSelectionMode newValue = (RatingSelectionMode)e.NewValue;
- source.OnSelectionModeChanged(oldValue, newValue);
- }
- /// <summary>
- /// SelectionModeProperty property changed handler.
- /// </summary>
- /// <param name="oldValue">Old value.</param>
- /// <param name="newValue">New value.</param>
- protected virtual void OnSelectionModeChanged(RatingSelectionMode oldValue, RatingSelectionMode newValue)
- {
- UpdateDisplayValues();
- }
- #endregion public RatingSelectionMode SelectionMode
- #region public double? Value
- /// <summary>
- /// Gets or sets the rating value.
- /// </summary>
- [SuppressMessage("Microsoft.Naming", "CA1721:PropertyNamesShouldNotMatchGetMethods", Justification = "Value is the logical name for this property.")]
- [TypeConverter(typeof(NullableConverter<double>))]
- public double? Value
- {
- get { return (double?)GetValue(ValueProperty); }
- set { SetValue(ValueProperty, value); }
- }
- /// <summary>
- /// Identifies the Value dependency property.
- /// </summary>
- public static readonly DependencyProperty ValueProperty =
- DependencyProperty.Register(
- "Value",
- typeof(double?),
- typeof(Rating),
- new PropertyMetadata(new double?(), OnValueChanged));
- /// <summary>
- /// ValueProperty property changed handler.
- /// </summary>
- /// <param name="d">Rating that changed its Value.</param>
- /// <param name="e">Event arguments.</param>
- private static void OnValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
- {
- Rating source = (Rating)d;
- double? oldValue = (double?)e.OldValue;
- double? newValue = (double?)e.NewValue;
- source.OnValueChanged(oldValue, newValue);
- }
- /// <summary>
- /// ValueProperty property changed handler.
- /// </summary>
- /// <param name="oldValue">Old value.</param>
- /// <param name="newValue">New value.</param>
- protected virtual void OnValueChanged(double? oldValue, double? newValue)
- {
- UpdateValues();
- #if SILVERLIGHT
- RoutedPropertyChangedEventHandler<double?> handler = ValueChanged;
- if (handler != null)
- {
- handler(this, new RoutedPropertyChangedEventArgs<double?>(oldValue, newValue));
- }
- #else
- RaiseEvent(new RoutedPropertyChangedEventArgs<double?>(oldValue, newValue, ValueChangedEvent));
- #endif
- }
- /// <summary>
- /// Updates the control when the items change.
- /// </summary>
- /// <param name="e">Information about the event.</param>
- protected override void OnItemsChanged(NotifyCollectionChangedEventArgs e)
- {
- EventHandler layoutUpdated = null;
- layoutUpdated =
- delegate
- {
- this.LayoutUpdated -= layoutUpdated;
- UpdateValues();
- UpdateDisplayValues();
- };
- this.LayoutUpdated += layoutUpdated;
- this.ItemCount = this.Items.Count;
- base.OnItemsChanged(e);
- }
- /// <summary>
- /// This event is raised when the value of the rating is changed.
- /// </summary>
- #if SILVERLIGHT
- public event RoutedPropertyChangedEventHandler<double?> ValueChanged;
- #else
- public static readonly RoutedEvent ValueChangedEvent = EventManager.RegisterRoutedEvent("ValueChanged", RoutingStrategy.Bubble, typeof(RoutedPropertyChangedEventHandler<double?>), typeof(Rating));
- /// <summary>
- /// This event is raised when the value of the rating is changed.
- /// </summary>
- public event RoutedPropertyChangedEventHandler<double?> ValueChanged
- {
- add { AddHandler(ValueChangedEvent, value); }
- remove { RemoveHandler(ValueChangedEvent, value); }
- }
- #endif
- #endregion public double? Value
- #if !SILVERLIGHT
- /// <summary>
- /// Initializes the static members of the ColumnDataPoint class.
- /// </summary>
- static Rating()
- {
- DefaultStyleKeyProperty.OverrideMetadata(typeof(Rating), new FrameworkPropertyMetadata(typeof(Rating)));
- }
- #endif
- /// <summary>
- /// Initializes a new instance of the Rating control.
- /// </summary>
- public Rating()
- {
- this.Interaction = new InteractionHelper(this);
- #if SILVERLIGHT
- this.DefaultStyleKey = typeof(Rating);
- this.ItemsControlHelper = new ItemsControlHelper(this);
- }
- /// <summary>
- /// Applies control template to the items control.
- /// </summary>
- public override void OnApplyTemplate()
- {
- ItemsControlHelper.OnApplyTemplate();
- base.OnApplyTemplate();
- #endif
- }
- /// <summary>
- /// This method is invoked when the mouse enters the rating item.
- /// </summary>
- /// <param name="e">Information about the event.</param>
- protected override void OnMouseEnter(MouseEventArgs e)
- {
- if (Interaction.AllowMouseEnter(e))
- {
- Interaction.UpdateVisualStateBase(true);
- }
- base.OnMouseEnter(e);
- }
- /// <summary>
- /// This method is invoked when the mouse leaves the rating item.
- /// </summary>
- /// <param name="e">Information about the event.</param>
- protected override void OnMouseLeave(MouseEventArgs e)
- {
- if (Interaction.AllowMouseLeave(e))
- {
- Interaction.UpdateVisualStateBase(true);
- }
- base.OnMouseLeave(e);
- }
- /// <summary>
- /// Provides handling for the Rating's MouseLeftButtonDown event.
- /// </summary>
- /// <param name="e">Event arguments.</param>
- protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
- {
- if (Interaction.AllowMouseLeftButtonDown(e))
- {
- Interaction.OnMouseLeftButtonDownBase();
- }
- base.OnMouseLeftButtonDown(e);
- }
- /// <summary>
- /// Provides handling for the Rating's MouseLeftButtonUp event.
- /// </summary>
- /// <param name="e">Event arguments.</param>
- protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e)
- {
- if (Interaction.AllowMouseLeftButtonUp(e))
- {
- Interaction.OnMouseLeftButtonUpBase();
- }
- base.OnMouseLeftButtonUp(e);
- }
- /// <summary>
- /// Updates the values of the rating items.
- /// </summary>
- private void UpdateValues()
- {
- IList<RatingItem> ratingItems = GetRatingItems().ToList();
- RatingItem oldSelectedItem = this.GetSelectedRatingItem();
- IEnumerable<Tuple<RatingItem, double>> itemAndWeights =
- EnumerableFunctions
- .Zip(
- ratingItems,
- ratingItems
- .Select(ratingItem => 1.0)
- .GetWeightedValues(Value.GetValueOrDefault()),
- (item, percent) => Tuple.Create(item, percent));
- foreach (Tuple<RatingItem, double> itemAndWeight in itemAndWeights)
- {
- itemAndWeight.First.Value = itemAndWeight.Second;
- }
- RatingItem newSelectedItem = this.GetSelectedRatingItem();
- // Notify when the selection changes
- if (oldSelectedItem != newSelectedItem)
- {
- if (newSelectedItem != null && AutomationPeer.ListenerExists(AutomationEvents.SelectionItemPatternOnElementSelected))
- {
- AutomationPeer peer = FrameworkElementAutomationPeer.CreatePeerForElement(newSelectedItem);
- if (peer != null)
- {
- peer.RaiseAutomationEvent(AutomationEvents.SelectionItemPatternOnElementSelected);
- }
- }
- if (oldSelectedItem != null && AutomationPeer.ListenerExists(AutomationEvents.SelectionItemPatternOnElementRemovedFromSelection))
- {
- AutomationPeer peer = FrameworkElementAutomationPeer.CreatePeerForElement(oldSelectedItem);
- if (peer != null)
- {
- peer.RaiseAutomationEvent(AutomationEvents.SelectionItemPatternOnElementRemovedFromSelection);
- }
- }
- }
- if (HoveredRatingItem == null)
- {
- DisplayValue = Value.GetValueOrDefault();
- }
- }
- /// <summary>
- /// Updates the value and actual value of the rating items.
- /// </summary>
- private void UpdateDisplayValues()
- {
- IList<RatingItem> ratingItems = GetRatingItems().ToList();
- IEnumerable<Tuple<RatingItem, double>> itemAndWeights =
- EnumerableFunctions
- .Zip(
- ratingItems,
- ratingItems
- .Select(ratingItem => 1.0)
- .GetWeightedValues(DisplayValue),
- (item, percent) => Tuple.Create(item, percent));
- RatingItem selectedItem = null;
- Tuple<RatingItem, double> selectedItemAndWeight = itemAndWeights.LastOrDefault(i => i.Second > 0.0);
- if (selectedItemAndWeight != null)
- {
- selectedItem = selectedItemAndWeight.First;
- }
- else
- {
- selectedItem = GetSelectedRatingItem();
- }
- foreach (Tuple<RatingItem, double> itemAndWeight in itemAndWeights)
- {
- if (SelectionMode == RatingSelectionMode.Individual && itemAndWeight.First != selectedItem)
- {
- itemAndWeight.First.DisplayValue = 0.0;
- }
- else
- {
- itemAndWeight.First.DisplayValue = itemAndWeight.Second;
- }
- }
- }
- /// <summary>
- /// Updates the hover states of the rating items.
- /// </summary>
- private void UpdateHoverStates()
- {
- if (HoveredRatingItem != null && !IsReadOnly)
- {
- IList<RatingItem> ratingItems = GetRatingItems().ToList();
- int indexOfItem = ratingItems.IndexOf(HoveredRatingItem);
- double total = ratingItems.Count();
- double filled = indexOfItem + 1;
- this.DisplayValue = filled / total;
- for (int cnt = 0; cnt < ratingItems.Count; cnt++)
- {
- RatingItem ratingItem = ratingItems[cnt];
- if (cnt <= indexOfItem && this.SelectionMode == RatingSelectionMode.Continuous)
- {
- VisualStates.GoToState(ratingItem, true, VisualStates.StateMouseOver);
- }
- else
- {
- IUpdateVisualState updateVisualState = (IUpdateVisualState) ratingItem;
- updateVisualState.UpdateVisualState(true);
- }
- }
- }
- else
- {
- this.DisplayValue = this.Value.GetValueOrDefault();
- foreach (IUpdateVisualState updateVisualState in GetRatingItems().OfType<IUpdateVisualState>())
- {
- updateVisualState.UpdateVisualState(true);
- }
- }
- }
- /// <summary>
- /// This method returns a container for the item.
- /// </summary>
- /// <returns>A container for the item.</returns>
- protected override DependencyObject GetContainerForItemOverride()
- {
- return new RatingItem();
- }
- /// <summary>
- /// Gets a value indicating whether the item is its own container.
- /// </summary>
- /// <param name="item">The item which may be a container.</param>
- /// <returns>A value indicating whether the item is its own container.
- /// </returns>
- protected override bool IsItemItsOwnContainerOverride(object item)
- {
- return item is RatingItem;
- }
- /// <summary>
- /// This method prepares a container to host an item.
- /// </summary>
- /// <param name="element">The container.</param>
- /// <param name="item">The item hosted in the container.</param>
- protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
- {
- RatingItem ratingItem = (RatingItem)element;
- object defaultForegroundValue = ratingItem.ReadLocalValue(Control.ForegroundProperty);
- if (defaultForegroundValue == DependencyProperty.UnsetValue)
- {
- ratingItem.SetBinding(Control.ForegroundProperty, new Binding("Foreground") { Source = this });
- }
- ratingItem.IsReadOnly = this.IsReadOnly;
- if (ratingItem.Style == null)
- {
- ratingItem.Style = this.ItemContainerStyle;
- }
- ratingItem.Click += RatingItemClick;
- ratingItem.MouseEnter += RatingItemMouseEnter;
- ratingItem.MouseLeave += RatingItemMouseLeave;
- ratingItem.ParentRating = this;
- base.PrepareContainerForItemOverride(element, item);
- }
- /// <summary>
- /// This method clears a container used to host an item.
- /// </summary>
- /// <param name="element">The container that hosts the item.</param>
- /// <param name="item">The item hosted in the container.</param>
- protected override void ClearContainerForItemOverride(DependencyObject element, object item)
- {
- RatingItem ratingItem = (RatingItem)element;
- ratingItem.Click -= RatingItemClick;
- ratingItem.MouseEnter -= RatingItemMouseEnter;
- ratingItem.MouseLeave -= RatingItemMouseLeave;
- ratingItem.ParentRating = null;
- if (ratingItem == HoveredRatingItem)
- {
- HoveredRatingItem = null;
- UpdateDisplayValues();
- UpdateHoverStates();
- }
- base.ClearContainerForItemOverride(element, item);
- }
- /// <summary>
- /// This method is invoked when a rating item's mouse enter event is
- /// invoked.
- /// </summary>
- /// <param name="sender">The source of the event.</param>
- /// <param name="e">Information about the event.</param>
- private void RatingItemMouseEnter(object sender, MouseEventArgs e)
- {
- HoveredRatingItem = (RatingItem) sender;
- UpdateHoverStates();
- }
- /// <summary>
- /// This method is invoked when a rating item's mouse leave event is
- /// invoked.
- /// </summary>
- /// <param name="sender">The source of the event.</param>
- /// <param name="e">Information about the event.</param>
- private void RatingItemMouseLeave(object sender, MouseEventArgs e)
- {
- HoveredRatingItem = null;
- UpdateDisplayValues();
- UpdateHoverStates();
- }
- /// <summary>
- /// Returns a sequence of rating items.
- /// </summary>
- /// <returns>A sequence of rating items.</returns>
- internal IEnumerable<RatingItem> GetRatingItems()
- {
- #if SILVERLIGHT
- return
- Enumerable
- .Range(0, this.Items.Count)
- .Select(index => (RatingItem)ItemContainerGenerator.ContainerFromIndex(index))
- .Where(ratingItem => ratingItem != null);
- #else
- // The query above returns null in WPF
- // Either way, WPF will already contain the RatingItem objects in the Items collection.
- return this.Items.Cast<RatingItem>();
- #endif
- }
- /// <summary>
- /// Selects a rating item.
- /// </summary>
- /// <param name="selectedRatingItem">The selected rating item.</param>
- internal void SelectRatingItem(RatingItem selectedRatingItem)
- {
- if (!this.IsReadOnly)
- {
- IList<RatingItem> ratingItems = GetRatingItems().ToList();
- IEnumerable<double> weights = ratingItems.Select(ratingItem => 1.0);
- double total = ratingItems.Count();
- double percent;
- if (total != 0)
- {
- percent = weights.Take(ratingItems.IndexOf(selectedRatingItem) + 1).Sum() / total;
- this.Value = percent;
- }
- }
- }
- /// <summary>
- /// This method is raised when a rating item value is selected.
- /// </summary>
- /// <param name="sender">The source of the event.</param>
- /// <param name="e">Information about the event.</param>
- private void RatingItemClick(object sender, RoutedEventArgs e)
- {
- if (!this.IsReadOnly)
- {
- RatingItem item = (RatingItem)sender;
- OnRatingItemValueSelected(item, 1.0);
- }
- }
- /// <summary>
- /// Returns the selected rating item.
- /// </summary>
- /// <returns>The selected rating item.</returns>
- private RatingItem GetSelectedRatingItem()
- {
- return this.GetRatingItems().LastOrDefault(ratingItem => ratingItem.Value > 0.0);
- }
- /// <summary>
- /// This method is invoked when the rating item value is changed.
- /// </summary>
- /// <param name="ratingItem">The rating item that has changed.</param>
- /// <param name="newValue">The new value.</param>
- protected virtual void OnRatingItemValueSelected(RatingItem ratingItem, double newValue)
- {
- List<RatingItem> ratingItems = GetRatingItems().ToList();
- double total = ratingItems.Count();
- double value =
- (ratingItems
- .Take(ratingItems.IndexOf(ratingItem))
- .Count() + newValue) / total;
- this.Value = value;
- }
- /// <summary>
- /// Returns a RatingItemAutomationPeer for use by the Silverlight
- /// automation infrastructure.
- /// </summary>
- /// <returns>A RatingItemAutomationPeer object for the RatingItem.</returns>
- protected override AutomationPeer OnCreateAutomationPeer()
- {
- return new RatingAutomationPeer(this);
- }
- /// <summary>
- /// Provides handling for the
- /// <see cref="E:System.Windows.UIElement.KeyDown" /> event when a key
- /// is pressed while the control has focus.
- /// </summary>
- /// <param name="e">
- /// A <see cref="T:System.Windows.Input.KeyEventArgs" /> that contains
- /// the event data.
- /// </param>
- /// <exception cref="T:System.ArgumentNullException">
- /// <paramref name="e " />is null.
- /// </exception>
- [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity", Justification = "Complexity metric is inflated by the switch statements")]
- protected override void OnKeyDown(KeyEventArgs e)
- {
- if (!Interaction.AllowKeyDown(e))
- {
- return;
- }
- base.OnKeyDown(e);
- if (e.Handled)
- {
- return;
- }
- switch (e.Key)
- {
- case Key.Left:
- {
- #if SILVERLIGHT
- RatingItem ratingItem = FocusManager.GetFocusedElement() as RatingItem;
- #else
- RatingItem ratingItem = FocusManager.GetFocusedElement(Application.Current.MainWindow) as RatingItem;
- #endif
- if (ratingItem != null)
- {
- ratingItem = GetRatingItemAtOffsetFrom(ratingItem, -1);
- }
- else
- {
- ratingItem = GetRatingItems().FirstOrDefault();
- }
- if (ratingItem != null)
- {
- if (ratingItem.Focus())
- {
- e.Handled = true;
- }
- }
- }
- break;
- case Key.Right:
- {
- #if SILVERLIGHT
- RatingItem ratingItem = FocusManager.GetFocusedElement() as RatingItem;
- #else
- RatingItem ratingItem = FocusManager.GetFocusedElement(Application.Current.MainWindow) as RatingItem;
- #endif
- if (ratingItem != null)
- {
- ratingItem = GetRatingItemAtOffsetFrom(ratingItem, 1);
- }
- else
- {
- ratingItem = GetRatingItems().FirstOrDefault();
- }
- if (ratingItem != null)
- {
- if (ratingItem.Focus())
- {
- e.Handled = true;
- }
- }
- }
- break;
- case Key.Add:
- {
- if (!this.IsReadOnly)
- {
- RatingItem ratingItem = GetSelectedRatingItem();
- if (ratingItem != null)
- {
- ratingItem = GetRatingItemAtOffsetFrom(ratingItem, 1);
- }
- else
- {
- ratingItem = GetRatingItems().FirstOrDefault();
- }
- if (ratingItem != null)
- {
- ratingItem.SelectValue();
- e.Handled = true;
- }
- }
- }
- break;
- case Key.Subtract:
- {
- if (!this.IsReadOnly)
- {
- RatingItem ratingItem = GetSelectedRatingItem();
- if (ratingItem != null)
- {
- ratingItem = GetRatingItemAtOffsetFrom(ratingItem, -1);
- }
- if (ratingItem != null)
- {
- ratingItem.SelectValue();
- e.Handled = true;
- }
- }
- }
- break;
- }
- }
- /// <summary>
- /// Gets a rating item at a certain index offset from another
- /// rating item.
- /// </summary>
- /// <param name="ratingItem">The rating item.</param>
- /// <param name="offset">The rating item at an offset from the
- /// index of the rating item.</param>
- /// <returns>The rating item at the offset.</returns>
- private RatingItem GetRatingItemAtOffsetFrom(RatingItem ratingItem, int offset)
- {
- IList<RatingItem> ratingItems = GetRatingItems().ToList();
- int index = ratingItems.IndexOf(ratingItem);
- if (index == -1)
- {
- return null;
- }
- index += offset;
- if (index >= 0 && index < ratingItems.Count)
- {
- ratingItem = ratingItems[index];
- }
- else
- {
- ratingItem = null;
- }
- return ratingItem;
- }
- /// <summary>
- /// Updates the visual state.
- /// </summary>
- /// <param name="useTransitions">A value indicating whether to use transitions.</param>
- void IUpdateVisualState.UpdateVisualState(bool useTransitions)
- {
- Interaction.UpdateVisualStateBase(useTransitions);
- }
- }
- }
|