In his recent post blog, Jafar Husain did a nice introduction to the Rating Control which we shipped with the July edition of the Silverlight Toolkit.  Jafar and I (the PM) spend quite a bit of time on this control making sure we provide a very powerful control that is both flexible, highly customizable and also easy to use.  We had a set of scenarios that were important for us to deliver on. One of them was what we refereed to as the “Netflix” scenario. In this scenario, the initial state of the rating control was displaying an average value (in reality, it is netflix’s best guess on how you would rate this movie). When user selects a value, the average disappears and new user selection is displayed.

Normal State: (Average_Value) Selected State (Value)
image image

If you take a look at the Rating Control API, we have a property called Value  but you will notice that we did not have an additional property for AverageValue. We debated for a while about the usefulness of such property. On one hand, most rating controls display an average value, so it would be natural to include a property for Average Value. Digging a little bit more, we realized that adding this property will be add a lot of redundancy to the control. The complexity of managing all the Visual States for both the Value and AverageValue would make the designer experience far more complicated than it needs to be when in the end there is a much simpler way to handle such scenario as we will see in this post. 

The trick to accomplishing this scenario is simply super-imposing two rating controls. One would capture the average value and the other one would capture user selection. I chose to use a UserControl to encapsulate this 2 controls:

NetflixRatingControl.xaml:

<UserControl x:Class="RatingSample.NetflixRatingControl"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
            xmlns:vsm="clr-namespace:System.Windows;assembly=System.Windows"
            xmlns:local="clr-namespace:RatingSample"
            xmlns:inputToolkit="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Input.Toolkit"
            xmlns:inputToolkitPrimitives="clr-namespace:System.Windows.Controls.Primitives;assembly=System.Windows.Controls.Input.Toolkit">
    <Grid>
        <Grid.Resources>
          ....
        </Grid.Resources>
        <!--ReadOnly Rating Control used to display average-->
        <inputToolkit:Rating IsReadOnly="True" x:Name="netflix_average" 
                             Visibility="{Binding Path=Value, ElementName=netflix, Converter={StaticResource ValueToVisibilityConverter}}"
                             ItemCount="5" Value="{Binding AvRating}" 
                             ItemContainerStyle="{StaticResource RatingItemStyle_Average}"/>
        <!--Rating Control used to display user selected rating-->
        <inputToolkit:Rating x:Name="netflix" ItemContainerStyle="{StaticResource RatingItemNetflixStyle}"  
                             ItemCount="5" />    
    </Grid>
</UserControl>

NetflixRatingControl.xaml.cs:

namespace RatingSample
{
    public partial class NetflixRatingControl : UserControl
    {
        public NetflixRatingControl()
        {
            InitializeComponent();
        }
        /// <summary>
        /// Represent the average value for all ratings.
        /// </summary>
        public double? AverageValue
        {
            get
            {
                return netflix_average.Value;
            }
            set
            {
                netflix_average.Value = value;
            }
        }
        /// <summary>
        /// Represent the current rating selected by user.
        /// </summary>
        public double? Value
        {
            get
            {
                return netflix.Value;
            }
            set
            {
                netflix.Value = value;
            }
        }

    }
Pretty straightforward!. You can see a live sample here
image

Download Source Code here