初步实现了一个绘制五角星的控件(http://blog.csdn.net/yysyangyangyangshan/article/details/9303005),但是在实际中有一种情况显示半颗五角星的。下面做一下改进,完善一下这个五角星控件。
功成名:TestFivePointStarLikeTaobao,
项目如图,
1、两种五角星的绘制方法
这两种计算坐标的方法比较重要。
五点画法,也是常用画法。
/// <summary> ///第一种画法 根据半径和圆心确定五个点 /// </summary> /// <param name="center"></param> /// <returns></returns> private PointCollection GetFivePoint1(Point center,double r) { double h1 = r * Math.Sin(18 * Math.PI / 180); double h2 = r * Math.Cos(18 * Math.PI / 180); double h3 = r * Math.Sin(36 * Math.PI / 180); double h4 = r * Math.Cos(36 * Math.PI / 180); Point p1 = new Point(r, center.X); Point p2 = new Point(r - h2, r - h1); Point p3 = new Point(r - h3, r + h4); Point p4 = new Point(r + h3, p3.Y); Point p5 = new Point(r + h2, p2.Y); List<Point> values = new List<Point>() { p1, p3, p5, p2, p4 }; PointCollection pcollect = new PointCollection(values); return pcollect; }
十点画法,这种比较方便画半颗五角星。
/// <summary> ///第二种画法 根据半径和圆心确定十个点 /// </summary> /// <param name="center"></param> /// <returns></returns> private PointCollection GetFivePoint2(Point center, double r) { int i; //两个圆的半径 和第一个点初始角度 //r1 = r / 2.5, r2 = r值的互换确定是正五角星还是倒五角星 double r1 = r / 2.5, r2 = r, g = 18; double pi = Math.PI; List<Point> values = new List<Point>(10);//十个点 List<Point> values1 = new List<Point>(5);//(内)外接五个点 List<Point> values2 = new List<Point>(5);//(外)内接五个点 for (i = 0; i < 5; i++) { //计算10个点的坐标 Point p1 = new Point(r1 * Math.Cos(g * pi / 180), r1 * Math.Sin(g * pi / 180)); Point p2 = new Point(r2 * Math.Cos((g + 36) * pi / 180), r2 * Math.Sin((g + 36) * pi / 180)); values1.Add(p1); values2.Add(p2); g += 72; } //左半边:3,4,5,6,7,8 //右半边:1,2,3,8,9,10 values.Add(values1[0]);//1 values.Add(values2[0]);//2 values.Add(values1[1]);//3 values.Add(values2[1]);//4 values.Add(values1[2]);//5 values.Add(values2[2]);//6 values.Add(values1[3]);//7 values.Add(values2[3]);//8 values.Add(values1[4]);//9 values.Add(values2[4]);//10 PointCollection pcollect = new PointCollection(values); return pcollect; }
五角星类代码:
public class FivePointStar:UserControl { private double radius = 20; private double currentPart = 1; private Brush selectBackground = new SolidColorBrush(Colors.YellowGreen); private Brush unselectBackgroud = new SolidColorBrush(Colors.DarkGray); /// <summary> /// 半径 /// </summary> public double Radius { get { object result = GetValue(RadiusProperty); if(result==null) { return radius; } return (double)result; } set { SetValue(RadiusProperty, value); this.InvalidateVisual(); } } public static DependencyProperty RadiusProperty = DependencyProperty.Register("Radius", typeof(double), typeof(FivePointStar), new UIPropertyMetadata()); /// <summary> /// 当前是否是一颗星 /// </summary> public double CurrentPart { get { object result = GetValue(CurrentPartProperty); if (result == null) { return currentPart; } return (double)result; } set { SetValue(CurrentPartProperty, value); this.InvalidateVisual(); } } public static DependencyProperty CurrentPartProperty = DependencyProperty.Register("CurrentPart", typeof(double), typeof(FivePointStar), new UIPropertyMetadata()); /// <summary> /// 选中颜色 /// </summary> public Brush SelectBackground { get { object result = GetValue(SelectBackgroundProperty); if (result == null) { return selectBackground; } return (Brush)result; } set { SetValue(SelectBackgroundProperty, value); //this.InvalidateVisual(); } } public static DependencyProperty SelectBackgroundProperty = DependencyProperty.Register("SelectBackground", typeof(Brush), typeof(FivePointStar), new UIPropertyMetadata()); /// <summary> /// 未选中颜色 /// </summary> public Brush UnSelectBackground { get { object result = GetValue(UnSelectBackgroundProperty); if (result == null) { return unselectBackgroud; } return (Brush)result; } set { SetValue(UnSelectBackgroundProperty, value); } } public static DependencyProperty UnSelectBackgroundProperty = DependencyProperty.Register("UnSelectBackground", typeof(Brush), typeof(FivePointStar), new UIPropertyMetadata()); public FivePointStar() : base() { this.Loaded += new RoutedEventHandler(FivePointStar_Loaded); } void FivePointStar_Loaded(object sender, RoutedEventArgs e) { //如果使用第一种画法就要开启此注释 //this.MinHeight = Radius * 2; //this.MaxHeight = Radius * 2; //this.MinWidth = Radius * 2; //this.MaxWidth = Radius * 2; //this.Background = Brushes.Transparent; this.MinHeight = 0; this.MaxHeight = 0; this.MinWidth = 0; this.MaxWidth = 0; this.Background = Brushes.Transparent; } protected override void OnRender(System.Windows.Media.DrawingContext dc) { base.OnRender(dc); Point center = new Point(); PointCollection Points = GetFivePoint2(center,Radius); Canvas ca = new Canvas(); if (CurrentPart == 1) { Polygon plg = new Polygon(); plg.Points = Points; plg.Stroke = Brushes.Transparent; plg.StrokeThickness = 2; plg.Fill = this.SelectBackground; plg.FillRule = FillRule.Nonzero; ca.Children.Add(plg); } else if (CurrentPart ==0) { Polygon plg = new Polygon(); plg.Points = Points; plg.Stroke = Brushes.Transparent; plg.StrokeThickness = 2; plg.Fill = this.UnSelectBackground; plg.FillRule = FillRule.Nonzero; ca.Children.Add(plg); } else { //半边五角星的画法 Polygon plg1 = new Polygon(); Polygon plg2 = new Polygon(); plg1.Points = Points; plg1.Stroke = Brushes.Transparent; plg1.StrokeThickness = 2; plg1.FillRule = FillRule.Nonzero; plg2.Points = Points; plg2.Stroke = Brushes.Transparent; plg2.StrokeThickness = 2; plg2.FillRule = FillRule.Nonzero; //左半边:3,4,5,6,7,8 //右半边:1,2,3,8,9,10 plg1.Points = new PointCollection() { Points[2], Points[3], Points[4], Points[5], Points[6], Points[7], }; plg1.Fill = SelectBackground; plg2.Points = new PointCollection() { Points[0], Points[1], Points[2], Points[7], Points[8], Points[9], }; plg2.Fill = UnSelectBackground; ca.Children.Add(plg1); ca.Children.Add(plg2); } ca.HorizontalAlignment = System.Windows.HorizontalAlignment.Stretch; ca.VerticalAlignment = System.Windows.VerticalAlignment.Stretch; this.Content = ca; //Brush b = new SolidColorBrush(Colors.Yellow); //Pen p = new Pen(b, 2); //var path = new Path(); //var gc = new GeometryConverter(); //path.Data = (Geometry)gc.ConvertFromString(string.Format("M {0} {1} {2} {3} {4} Z", // Points[0], Points[1], Points[2], Points[3], Points[4])); //path.Fill = Brushes.Yellow; //dc.DrawGeometry(b, p, path.Data); } /// <summary> ///第一种画法 根据半径和圆心确定五个点 /// </summary> /// <param name="center"></param> /// <returns></returns> private PointCollection GetFivePoint1(Point center,double r) { double h1 = r * Math.Sin(18 * Math.PI / 180); double h2 = r * Math.Cos(18 * Math.PI / 180); double h3 = r * Math.Sin(36 * Math.PI / 180); double h4 = r * Math.Cos(36 * Math.PI / 180); Point p1 = new Point(r, center.X); Point p2 = new Point(r - h2, r - h1); Point p3 = new Point(r - h3, r + h4); Point p4 = new Point(r + h3, p3.Y); Point p5 = new Point(r + h2, p2.Y); List<Point> values = new List<Point>() { p1, p3, p5, p2, p4 }; PointCollection pcollect = new PointCollection(values); return pcollect; } /// <summary> ///第二种画法 根据半径和圆心确定十个点 /// </summary> /// <param name="center"></param> /// <returns></returns> private PointCollection GetFivePoint2(Point center, double r) { int i; //两个圆的半径 和第一个点初始角度 //r1 = r / 2.5, r2 = r值的互换确定是正五角星还是倒五角星 double r1 = r / 2.5, r2 = r, g = 18; double pi = Math.PI; List<Point> values = new List<Point>(10);//十个点 List<Point> values1 = new List<Point>(5);//(内)外接五个点 List<Point> values2 = new List<Point>(5);//(外)内接五个点 for (i = 0; i < 5; i++) { //计算10个点的坐标 Point p1 = new Point(r1 * Math.Cos(g * pi / 180), r1 * Math.Sin(g * pi / 180)); Point p2 = new Point(r2 * Math.Cos((g + 36) * pi / 180), r2 * Math.Sin((g + 36) * pi / 180)); values1.Add(p1); values2.Add(p2); g += 72; } //左半边:3,4,5,6,7,8 //右半边:1,2,3,8,9,10 values.Add(values1[0]);//1 values.Add(values2[0]);//2 values.Add(values1[1]);//3 values.Add(values2[1]);//4 values.Add(values1[2]);//5 values.Add(values2[2]);//6 values.Add(values1[3]);//7 values.Add(values2[3]);//8 values.Add(values1[4]);//9 values.Add(values2[4]);//10 PointCollection pcollect = new PointCollection(values); return pcollect; } }
这个可以直接使用,效果如下
2、多颗五角星控件
前台,
<UserControl x:Class="TestFivePointStarLikeTaobao.FivePointStarGroup" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:local="clr-namespace:TestFivePointStarLikeTaobao" mc:Ignorable="d"> <Grid x:Name="groupGrid" Background="Transparent"> <ListBox x:Name="lsbchildCategory" ItemsSource="{Binding ChildCategoryList,IsAsync=True}" Background="WhiteSmoke" BorderThickness="0"> <ListBox.ItemTemplate> <DataTemplate> <local:FivePointStar Radius="{Binding Radius}" CurrentPart="{Binding CurrentValue}" Tag="{Binding ID}" Margin="{Binding Margins}" SelectBackground="{Binding SelectBackground}" UnSelectBackground="{Binding UnselectBackgroud}" MouseDown="FivePointStar_MouseDown"/> </DataTemplate> </ListBox.ItemTemplate> <ListBox.ItemsPanel> <ItemsPanelTemplate> <StackPanel VerticalAlignment="Center" Orientation="Horizontal" HorizontalAlignment="Center"/> </ItemsPanelTemplate> </ListBox.ItemsPanel> </ListBox> </Grid> </UserControl>
后台,
/// <summary> /// FivePointStarGroup.xaml 的交互逻辑 /// </summary> public partial class FivePointStarGroup : UserControl { private double radius = 20; private double itemsCount = 5; private double selectCount = 5; private Brush selectBackground = new SolidColorBrush(Colors.YellowGreen); private Brush unselectBackgroud = new SolidColorBrush(Colors.DarkGray); /// <summary> /// 五角星半径 /// </summary> public double Radius { get { object result = GetValue(RadiusProperty); if(result==null) { return radius; } return (double)result; } set { SetValue(RadiusProperty, value); } } public static DependencyProperty RadiusProperty = DependencyProperty.Register("Radius", typeof(double), typeof(FivePointStarGroup), new UIPropertyMetadata()); /// <summary> /// 五角星个数 /// </summary> public double ItemsCount { get { object result = GetValue(ItemsCountProperty); if (result == null) { return itemsCount; } return (double)result; } set { SetValue(ItemsCountProperty, value); InitialData(); this.InvalidateVisual(); } } public static DependencyProperty ItemsCountProperty = DependencyProperty.Register("ItemsCount", typeof(double), typeof(FivePointStar), new UIPropertyMetadata()); /// <summary> /// 选中的五角星个数 /// </summary> public double SelectCount { get { object result = GetValue(SelectCountProperty); if (result == null) { return selectCount; } return (double)result; } set { SetValue(SelectCountProperty, value); InitialData(); this.InvalidateVisual(); } } public static DependencyProperty SelectCountProperty = DependencyProperty.Register("SelectCount", typeof(double), typeof(FivePointStar), new UIPropertyMetadata()); public event RoutedEventHandler SelectCountChangeEvent { add { AddHandler(SelectCountChangePropertyEvent, value); } remove { RemoveHandler(SelectCountChangePropertyEvent, value); } } /// <summary> /// 选中颜色 /// </summary> public Brush SelectBackground { get { object result = GetValue(SelectBackgroundProperty); if (result == null) { return selectBackground; } return (Brush)result; } set { SetValue(SelectBackgroundProperty, value); } } public static DependencyProperty SelectBackgroundProperty = DependencyProperty.Register("SelectBackground", typeof(Brush), typeof(FivePointStarGroup), new UIPropertyMetadata()); /// <summary> /// 未选中颜色 /// </summary> public Brush UnSelectBackground { get { object result = GetValue(UnSelectBackgroundProperty); if (result == null) { return unselectBackgroud; } return (Brush)result; } set { SetValue(UnSelectBackgroundProperty, value); } } public static DependencyProperty UnSelectBackgroundProperty = DependencyProperty.Register("UnSelectBackground", typeof(Brush), typeof(FivePointStarGroup), new UIPropertyMetadata()); public static RoutedEvent SelectCountChangePropertyEvent = EventManager.RegisterRoutedEvent("SelectCountChangeEvent", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(Control)); public FivePointStarGroup() { InitializeComponent(); this.Loaded += new RoutedEventHandler(FivePointStarGroup_Loaded); } void FivePointStarGroup_Loaded(object sender, RoutedEventArgs e) { InitialData(); } private void InitialData() { List<FivePointStarModel> list = new List<FivePointStarModel>(); int count = Convert.ToInt32(this.ItemsCount); if (count <= 0) { count = Convert.ToInt32(this.itemsCount); } for (int i = 0; i < count; i++) { FivePointStarModel item = new FivePointStarModel(); item.ID = i + 1; item.Radius = Radius; item.SelectBackground = SelectBackground; item.UnselectBackgroud = UnSelectBackground; item.Margins = new Thickness(Radius, 0, Radius, 0); //在此设置星形显示的颜色 if ((i + 1) > SelectCount && ((i + 1 - SelectCount) > 0) && (i + 1 - SelectCount) < 1) { item.CurrentValue = 0.5; } else if ((i + 1) > SelectCount) { item.CurrentValue = 0; } else { item.CurrentValue = 1; } list.Add(item); } this.lsbchildCategory.ItemsSource = list; } private void FivePointStar_MouseDown(object sender, MouseButtonEventArgs e) { FivePointStar m = sender as FivePointStar; if (m == null) { return; } int index = Convert.ToInt32(m.Tag); this.SelectCount = index; RaiseEvent(new RoutedEventArgs(SelectCountChangePropertyEvent, sender)); } }
用于绑定的类,
public class FivePointStarModel:NotifyObject { private int id; private double radius = 20; private double currentValue = 1; private Brush selectBackground = new SolidColorBrush(Colors.GreenYellow); private Brush unselectBackgroud = new SolidColorBrush(Colors.DarkGray); private Thickness margins = new Thickness(0); public int ID { get { return id; } set { id = value; this.OnPropertyChanged("Radius"); } } public double Radius { get { return radius; } set { radius = value; this.OnPropertyChanged("Radius"); } } public double CurrentValue { get { return currentValue; } set { currentValue = value; this.OnPropertyChanged("CurrentValue"); } } public Brush SelectBackground { get { return selectBackground; } set { selectBackground = value; this.OnPropertyChanged("SelectBackground"); } } public Brush UnselectBackgroud { get { return unselectBackgroud; } set { unselectBackgroud = value; this.OnPropertyChanged("UnselectBackgroud"); } } public Thickness Margins { get { return margins; } set { margins = value; this.OnPropertyChanged("Radius"); } } } public abstract class NotifyObject : INotifyPropertyChanged { public void OnPropertyChanged(string propname) { if (this.PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(propname)); } } public event PropertyChangedEventHandler PropertyChanged; }
这个控件中,增加了设置一颗五角星的三种状态:全选中、全部选中,选中半颗。
对于绑定的类,增加了Margin的绑定。
3、测试调用
前台,
<Window x:Class="TestFivePointStarLikeTaobao.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="446" Width="849" xmlns:my="clr-namespace:TestFivePointStarLikeTaobao"> <Grid> <my:FivePointStarGroup HorizontalAlignment="Stretch" Margin="136,65,361,281" x:Name="fivePointStarGroup1" VerticalAlignment="Stretch" SelectBackground="GreenYellow" Radius="30" Visibility="Visible" UnSelectBackground="DarkGray" ItemsCount="5" SelectCount="5" /> <TextBox Height="30" HorizontalAlignment="Left" Margin="202,232,0,0" Name="textBox1" VerticalAlignment="Top" Width="120" FontSize="18" /> <Button Content="设 置" Height="46" HorizontalAlignment="Left" Margin="365,192,0,0" Name="button1" VerticalAlignment="Top" Width="142" FontSize="18" Click="button1_Click" /> <TextBox Height="30" HorizontalAlignment="Left" Margin="202,159,0,0" Name="textBox2" VerticalAlignment="Top" Width="120" FontSize="18"/> <TextBlock Height="23" HorizontalAlignment="Left" Margin="136,232,0,0" Name="textBlock1" Text="选 中:" VerticalAlignment="Top" FontSize="18"/> <TextBlock Height="23" HorizontalAlignment="Left" Margin="136,159,0,0" Name="textBlock2" Text="总 数:" VerticalAlignment="Top" FontSize="18"/> <my:FivePointStar HorizontalAlignment="Left" Margin="666,232,0,0" x:Name="fivePointStar1" VerticalAlignment="Top" Height="0" Width="0" Radius="30" CurrentPart="1"/> </Grid> </Window>
后台,
/// <summary> /// MainWindow.xaml 的交互逻辑 /// </summary> public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); InitialData(); this.fivePointStarGroup1.SelectCountChangeEvent += new RoutedEventHandler(fivePointStarGroup1_SelectCountChangeEvent); } private void InitialData() { this.textBox1.Text = this.fivePointStarGroup1.SelectCount.ToString(); this.textBox2.Text = this.fivePointStarGroup1.ItemsCount.ToString(); } void fivePointStarGroup1_SelectCountChangeEvent(object sender, RoutedEventArgs e) { InitialData(); } private void button1_Click(object sender, RoutedEventArgs e) { double selectCount = Convert.ToDouble(this.textBox1.Text); int allCount = Convert.ToInt32(this.textBox2.Text); if (allCount < selectCount) { MessageBox.Show("参数设置错误!"); return; } this.fivePointStarGroup1.ItemsCount = allCount; this.fivePointStarGroup1.SelectCount = selectCount; } }
最终效果图,
这样可以适用于大部分的评级功能。
代码下载:
http://download.csdn.net/detail/yysyangyangyangshan/5743911