WPF-22:WPF绘制五角星改进版(增加半个五角星的绘制)
 初步实现了一个绘制五角星的控件(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
 
 
 
 
                     
                    
                 
                    
                
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号