您的位置:首页 > 其它

WPF-22:WPF绘制五角星改进版(增加半个五角星的绘制)

2013-07-12 17:13 423 查看
初步实现了一个绘制五角星的控件(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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: