您的位置:首页 > 其它

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

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