In my day work I had to make a star rating control and I thought it would be interesting to reuse the slider control for that purpose. I also wanted it to be pure xaml. I use a shape proposed by Kiran Kumar which I slightly modified.
Here is a visual (nothing really surprising though):
If you want to try, simply copy/paste the following piece of xaml to your favorite xaml editor (I used Kaxaml, which is a great tool):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 | <Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Background="#2d2d20"> <Page.Resources> <SolidColorBrush x:Key="NoStar" Color="#29ffffff" /> <SolidColorBrush x:Key="Star" Color="Yellow" /> <Style x:Key="StarRatingShapeStyle" TargetType="Polygon"> <Setter Property="Width" Value="12" /> <Setter Property="Height" Value="12" /> <Setter Property="Fill" Value="{StaticResource NoStar}" /> <Setter Property="Points" Value="9,2 11,7 17,7 12,10 14,15 9,12 4,15 6,10 1,7 7,7" /> <Setter Property="Stretch" Value="Fill" /> <Setter Property="Stroke" Value="White" /> <Setter Property="StrokeLineJoin" Value="Round" /> <Setter Property="StrokeThickness" Value=".5" /> <Setter Property="IsHitTestVisible" Value="False" /> </Style> <Style x:Key="RatingSliderRepeatButtonStyle" TargetType="{x:Type RepeatButton}"> <Setter Property="Padding" Value="0" /> <Setter Property="Margin" Value="0" /> <Setter Property="Background" Value="Transparent" /> <Setter Property="Template"> <Setter.Value> <ControlTemplate> <Border Background="{TemplateBinding Background}" BorderThickness="0" /> </ControlTemplate> </Setter.Value> </Setter> </Style> <Style x:Key="RatingSliderThumbStyle" TargetType="{x:Type Thumb}"> <Setter Property="OverridesDefaultStyle" Value="true" /> <Setter Property="Focusable" Value="False" /> <Setter Property="Padding" Value="0" /> <Setter Property="Margin" Value="0" /> <Setter Property="Background" Value="Transparent" /> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type Thumb}"> <Border Background="{TemplateBinding Background}" BorderThickness="0" /> </ControlTemplate> </Setter.Value> </Setter> </Style> <Style x:Key="StarRatingSliderStyle" TargetType="Slider"> <Setter Property="Minimum" Value="0" /> <Setter Property="Maximum" Value="5" /> <Setter Property="SmallChange" Value="1" /> <Setter Property="LargeChange" Value="1" /> <Setter Property="TickFrequency" Value="1" /> <Setter Property="IsSnapToTickEnabled" Value="True" /> <Setter Property="IsMoveToPointEnabled" Value="True" /> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="Slider"> <Grid> <Track x:Name="PART_Track" > <Track.DecreaseRepeatButton> <RepeatButton Style="{StaticResource RatingSliderRepeatButtonStyle}" Command="{x:Static Slider.DecreaseLarge}" /> </Track.DecreaseRepeatButton> <Track.IncreaseRepeatButton> <RepeatButton Style="{StaticResource RatingSliderRepeatButtonStyle}" Command="{x:Static Slider.IncreaseLarge}" /> </Track.IncreaseRepeatButton> <Track.Thumb> <Thumb x:Name="PART_Thumb" Style="{StaticResource RatingSliderThumbStyle}" /> </Track.Thumb> </Track> <StackPanel Orientation="{TemplateBinding Orientation}"> <Polygon x:Name="S5" Style="{StaticResource StarRatingShapeStyle}" /> <Polygon x:Name="S4" Style="{StaticResource StarRatingShapeStyle}" /> <Polygon x:Name="S3" Style="{StaticResource StarRatingShapeStyle}" /> <Polygon x:Name="S2" Style="{StaticResource StarRatingShapeStyle}" /> <Polygon x:Name="S1" Style="{StaticResource StarRatingShapeStyle}" /> </StackPanel> </Grid> <ControlTemplate.Triggers> <Trigger Property="Value" Value="1"> <Setter TargetName="S1" Property="Fill" Value="{StaticResource Star}"/> <Setter TargetName="S2" Property="Fill" Value="{StaticResource NoStar}"/> <Setter TargetName="S3" Property="Fill" Value="{StaticResource NoStar}"/> <Setter TargetName="S4" Property="Fill" Value="{StaticResource NoStar}"/> <Setter TargetName="S5" Property="Fill" Value="{StaticResource NoStar}"/> </Trigger> <Trigger Property="Value" Value="2"> <Setter TargetName="S1" Property="Fill" Value="{StaticResource Star}"/> <Setter TargetName="S2" Property="Fill" Value="{StaticResource Star}"/> <Setter TargetName="S3" Property="Fill" Value="{StaticResource NoStar}"/> <Setter TargetName="S4" Property="Fill" Value="{StaticResource NoStar}"/> <Setter TargetName="S5" Property="Fill" Value="{StaticResource NoStar}"/> </Trigger> <Trigger Property="Value" Value="3"> <Setter TargetName="S1" Property="Fill" Value="{StaticResource Star}"/> <Setter TargetName="S2" Property="Fill" Value="{StaticResource Star}"/> <Setter TargetName="S3" Property="Fill" Value="{StaticResource Star}"/> <Setter TargetName="S4" Property="Fill" Value="{StaticResource NoStar}"/> <Setter TargetName="S5" Property="Fill" Value="{StaticResource NoStar}"/> </Trigger> <Trigger Property="Value" Value="4"> <Setter TargetName="S1" Property="Fill" Value="{StaticResource Star}"/> <Setter TargetName="S2" Property="Fill" Value="{StaticResource Star}"/> <Setter TargetName="S3" Property="Fill" Value="{StaticResource Star}"/> <Setter TargetName="S4" Property="Fill" Value="{StaticResource Star}"/> <Setter TargetName="S5" Property="Fill" Value="{StaticResource NoStar}"/> </Trigger> <Trigger Property="Value" Value="5"> <Setter TargetName="S1" Property="Fill" Value="{StaticResource Star}"/> <Setter TargetName="S2" Property="Fill" Value="{StaticResource Star}"/> <Setter TargetName="S3" Property="Fill" Value="{StaticResource Star}"/> <Setter TargetName="S4" Property="Fill" Value="{StaticResource Star}"/> <Setter TargetName="S5" Property="Fill" Value="{StaticResource Star}"/> </Trigger> </ControlTemplate.Triggers> </ControlTemplate> </Setter.Value> </Setter> </Style> </Page.Resources> <StackPanel> <Slider x:Name="Ranking" Orientation="Vertical" HorizontalAlignment="Center" Background="Transparent" Style="{StaticResource StarRatingSliderStyle}" /> <Slider x:Name="Test" Orientation="Horizontal" Minimum="0" Maximum="5" Width="200" Height="200" IsSnapToTickEnabled="True" TickFrequency="1" Value="{Binding Value, ElementName=Ranking}" /> </StackPanel> </Page> |
This xaml implementation is not completely usable because of two small issues:
- Depending on where you click on a star (above or below the middle) you got different behaviors. But it could be easily solved with a converter that would ceil or floor the value.
- Horizontal and vertical orientation is handled, but in horizontal orientation the order is reversed. I guess I should not use the Stackpanel orientation but rather a LayoutTransform.