初步实现了一个绘制五角星的控件(http://blog.csdn.net/yysyangyangyangshan/article/details/9303005),但是在实际中有一种情况显示半颗五角星的。下面做一下改进,完善一下这个五角星控件。
功成名:TestFivePointStarLikeTaobao,
项目如图,
1、两种五角星的绘制方法
这两种计算坐标的方法比较重要。
五点画法,也是常用画法。
2、多颗五角星控件
前台,
对于绑定的类,增加了Margin的绑定。
3、测试调用
前台,
这样可以适用于大部分的评级功能。
代码下载: http://download.csdn.net/detail/yysyangyangyangshan/5743911
功成名: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