`
he91_com
  • 浏览: 376000 次
文章分类
社区版块
存档分类
最新评论

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

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics