1:XAML
<Style TargetType="local:PieChart">
<Setter Property="Foreground" Value="#FF767676" />
<Setter Property="Palette">
<Setter.Value>
<local:PaletteCollection>
<Style TargetType="Path">
<Setter Property="Fill" Value="#FF25a0db" />
<Setter Property="Stroke" Value="#FFFFFF" />
</Style>
<Style TargetType="Path">
<Setter Property="Fill" Value="#FF9cd60f" />
<Setter Property="Stroke" Value="#FFFFFF" />
</Style>
<Style TargetType="Path">
<Setter Property="Fill" Value="#FFeb7a2a" />
<Setter Property="Stroke" Value="#FFFFFF" />
</Style>
<Style TargetType="Path">
<Setter Property="Fill" Value="#FFd4df32" />
<Setter Property="Stroke" Value="#FFFFFF" />
</Style>
<Style TargetType="Path">
<Setter Property="Fill" Value="#FFcc0000" />
<Setter Property="Stroke" Value="#FFFFFF" />
</Style>
<Style TargetType="Path">
<Setter Property="Fill" Value="#FFE8BC34" />
<Setter Property="Stroke" Value="#FFFFFF" />
</Style>
<Style TargetType="Path">
<Setter Property="Fill" Value="#FF00ABA9" />
<Setter Property="Stroke" Value="#FFFFFF" />
</Style>
<Style TargetType="Path">
<Setter Property="Fill" Value="#FF339933" />
<Setter Property="Stroke" Value="#FFFFFF" />
</Style>
</local:PaletteCollection>
</Setter.Value>
</Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:PieChart">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid x:Name="gChart" Grid.Column="0">
</Grid>
<Grid x:Name="gLegend" Grid.Column="1" Width="{TemplateBinding LegendWidth}" >
<ScrollViewer Margin="20,0,0,0" BorderThickness="0" HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto">
<StackPanel x:Name="spLegend" Orientation="Vertical" />
</ScrollViewer>
</Grid>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
2:C#后台
/// <summary>
/// 饼状图控件
/// 参数说明:
/// Label:类型标签,传值的类型标签,如Dictionary的Key;
/// Value:值,如Dictionary的Value;
/// ShowLabel:是否显示饼图标签;
/// ShowLegend:是否显示图例;
/// Palette:饼图的颜色板,可以用PaletteCollection类添加,默认颜色有8种;
/// LegendWidth:图例的宽度;
/// ItemsSource:饼图的数据源;
///
/// author:hzw
/// time:2013/08/20
/// </summary>
[TemplatePart(Name = "gLegend", Type = typeof(Grid))]
[TemplatePart(Name = "gChart", Type = typeof(Grid))]
[TemplatePart(Name = "spLegend", Type = typeof(StackPanel))]
public class PieChart : Control
{
/// <summary>
/// 类型标签
/// </summary>
public string Label { get; set; }
/// <summary>
/// 值
/// </summary>
public string Value { get; set; }
FxChart c = new FxChart("",null,"");
/// <summary>
/// 构造函数
/// </summary>
public PieChart()
{
this.DefaultStyleKey = typeof(PieChart);
SizeChanged += new SizeChangedEventHandler(PieChart_SizeChanged);
}
/// <summary>
/// 尺寸变化事件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void PieChart_SizeChanged(object sender, SizeChangedEventArgs e)
{
if (ItemsSource != null)
{
BindData();
}
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
if (ItemsSource != null)
{
BindData();
}
}
#region 依赖性属性设置
public static readonly DependencyProperty ShowLabelProperty = DependencyProperty.Register("ShowLabel", typeof(bool), typeof(PieChart), new PropertyMetadata(false, new PropertyChangedCallback(OnShowLabelPropertyChanged)));
/// <summary>
/// 显示标签
/// </summary>
/// <param name="d"></param>
/// <param name="e"></param>
private static void OnShowLabelPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
PieChart obj = (PieChart)d;
obj.BindData();
}
public bool ShowLabel
{
get { return (bool)GetValue(ShowLabelProperty); }
set { SetValue(ShowLabelProperty, value); this.BindData(); }
}
public static readonly DependencyProperty ShowLegendProperty = DependencyProperty.Register("ShowLegend", typeof(bool), typeof(PieChart), new PropertyMetadata(false, new PropertyChangedCallback(OnShowLegendPropertyChanged)));
/// <summary>
/// 是否显示图例
/// </summary>
/// <param name="d"></param>
/// <param name="e"></param>
private static void OnShowLegendPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
PieChart obj = (PieChart)d;
obj.BindData();
}
public bool ShowLegend
{
get { return (bool)GetValue(ShowLegendProperty); }
set { SetValue(ShowLegendProperty, value); this.BindData(); }
}
public static readonly DependencyProperty PaletteProperty = DependencyProperty.Register("Palette", typeof(PaletteCollection), typeof(PieChart), new PropertyMetadata(new PaletteCollection()));
/// <summary>
/// 调色板
/// </summary>
public PaletteCollection Palette
{
get { return (PaletteCollection)GetValue(PaletteProperty); }
set
{
SetValue(PaletteProperty, value);
}
}
public static readonly DependencyProperty LegendWidthProperty = DependencyProperty.Register("LegendWidth", typeof(double), typeof(PieChart), new PropertyMetadata((double)80, new PropertyChangedCallback(OnLegendWidthPropertyChanged)));
/// <summary>
/// 图例宽度
/// </summary>
/// <param name="d"></param>
/// <param name="e"></param>
private static void OnLegendWidthPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
PieChart obj = (PieChart)d;
obj.BindData();
}
public double LegendWidth
{
get { return (double)GetValue(LegendWidthProperty); }
set
{
SetValue(LegendWidthProperty, value);
}
}
public static readonly DependencyProperty ItemsSourceProperty = DependencyProperty.Register("ItemsSource", typeof(IEnumerable), typeof(PieChart), new PropertyMetadata(null, new PropertyChangedCallback(OnItemsSourcePropertyChanged)));
/// <summary>
/// 数据源
/// </summary>
/// <param name="d"></param>
/// <param name="e"></param>
private static void OnItemsSourcePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
PieChart obj = (PieChart)d;
obj.BindData();
}
public IEnumerable ItemsSource
{
get { return (IEnumerable)GetValue(ItemsSourceProperty); }
set
{
SetValue(ItemsSourceProperty, value);
BindData();
}
}
#endregion
const double ChartSpace = 100;
const double LabelSpace = 1;
List<Path> _List = new List<Path>();
#region 绑定数据源
/// <summary>
/// 绑定数据
/// </summary>
private void BindData()
{
string labelPath = this.Label;
string valuePath = this.Value;
if (this.ActualWidth == double.NaN || this.ActualWidth == 0) return;
Grid gLegend = (Grid)this.GetTemplateChild("gLegend");
Grid gChart = (Grid)this.GetTemplateChild("gChart");
StackPanel spLegend = (StackPanel)this.GetTemplateChild("spLegend");
if (gLegend == null || gChart == null || spLegend == null) return;
gChart.Children.Clear();
spLegend.Children.Clear();
_List.Clear();
gLegend.Visibility = ShowLegend ? Visibility.Visible : Visibility.Collapsed;
double chartSpace = ChartSpace;
//饼图位置
double chartWidth = this.ActualWidth - (ShowLegend ? LegendWidth : 0);
Point centerPoint = new Point(chartWidth / 2, this.ActualHeight / 2);
if (chartWidth > this.ActualHeight) chartWidth = this.ActualHeight;
if (ShowLabel && chartWidth > chartSpace) chartWidth = chartWidth - chartSpace;
//初始角度
double startAngle = 0;
//初始点
Point startPoint = new Point(centerPoint.X, centerPoint.Y - (chartWidth / 2));
if (ItemsSource != null && !string.IsNullOrEmpty(labelPath) && !string.IsNullOrEmpty(valuePath))
{
//取总数
double sum = 0;
foreach (object obj in ItemsSource)
{
PropertyInfo piLabel = obj.GetType().GetProperty(labelPath);
PropertyInfo piValue = obj.GetType().GetProperty(valuePath);
if (piLabel == null)
throw new Exception("标签错误!");
if (piValue == null)
throw new Exception("值错误!");
object v = piValue.GetValue(obj, null);
if (v != null)
{
sum += double.Parse(v.ToString());
}
}
int paletteIndex = 0;
Brush fill = new SolidColorBrush(Color.FromArgb(0xFF, 0xBA, 0xBA, 0xBA));
//Brush stroke = new SolidColorBrush(Colors.White);
Style style = new Style();
style.Setters.Add(new Setter { Property = Path.FillProperty, Value = new SolidColorBrush(Color.FromArgb(0xFF, 0xBA, 0xBA, 0xBA)) });
style.Setters.Add(new Setter { Property = Path.StrokeProperty, Value = new SolidColorBrush(Colors.White) });
foreach (object obj in ItemsSource)
{
//获取调色板
if (Palette != null && Palette.Count > 0)
{
style = Palette[paletteIndex];
foreach (Setter setter in style.Setters)
{
if (setter.Property == Path.FillProperty)
fill = (Brush)setter.Value;
//if (setter.Property == Path.StrokeProperty)
// stroke = (Brush)setter.Value;
}
paletteIndex++;
if (paletteIndex >= Palette.Count)
paletteIndex = 0;
}
PropertyInfo piLabel = obj.GetType().GetProperty(Label);
PropertyInfo piValue = obj.GetType().GetProperty(Value);
string label = piLabel.GetValue(obj, null).ToString();
double value = double.Parse(piValue.GetValue(obj, null).ToString());
//插入图例
Grid gridLegendItem = new Grid { Margin = new Thickness(0, 2, 0, 0) };
gridLegendItem.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(20) });
gridLegendItem.ColumnDefinitions.Add(new ColumnDefinition());
Rectangle rectLengendItem = new Rectangle { Fill = fill, Width = 12, Height = 12, VerticalAlignment = VerticalAlignment.Top, Margin = new Thickness(0, 2, 0, 0) };
TextBlock tbLengendItem = new TextBlock { TextWrapping = TextWrapping.Wrap };
//设置图例说明
tbLengendItem.Text = label;
Grid.SetColumn(tbLengendItem, 1);
gridLegendItem.Children.Add(rectLengendItem);
gridLegendItem.Children.Add(tbLengendItem);
spLegend.Children.Add(gridLegendItem);
//当前角度
double cAngle = value * 360 / sum + startAngle;
Point curPoint = startPoint;
//计算坐标
curPoint.X = centerPoint.X + (chartWidth / 2) * Math.Cos((cAngle - 90) * Math.PI / 180);
curPoint.Y = centerPoint.Y + (chartWidth / 2) * Math.Sin((cAngle - 90) * Math.PI / 180);
//插入块
Path path = new Path();
path.Style = style;
//path.Fill = fill;
//path.Stroke = stroke;
path.StrokeThickness = 1;
PathFigure pathFigure = new PathFigure { IsClosed = true };
pathFigure.StartPoint = centerPoint;
LineSegment line = new LineSegment();
line.Point = startPoint;
pathFigure.Segments.Add(line);
//饼图的圆弧
ArcSegment arc = new ArcSegment();
arc.Size = new Size(chartWidth / 2, chartWidth / 2);
arc.Point = curPoint;
arc.SweepDirection = SweepDirection.Clockwise;
pathFigure.Segments.Add(arc);
PathGeometry pathGeometry = new PathGeometry();
pathGeometry.Figures.Add(pathFigure);
path.Data = pathGeometry;
gChart.Children.Add(path);
_List.Add(path);
path.Tag = obj;
//饼图标识显示
if (ShowLabel)
{
//计算中间角度
double mAngle = value * 180 / sum + startAngle;
//计算Label坐标
double lX = centerPoint.X + (chartWidth / 2) * Math.Cos((mAngle - 90) * Math.PI / 180);
double lY = centerPoint.Y + (chartWidth / 2) * Math.Sin((mAngle - 90) * Math.PI / 180);
//饼图注记显示
TextBlock tbLabel = new TextBlock { TextWrapping = TextWrapping.Wrap, TextAlignment = TextAlignment.Center };
//tbLabel.Text = label + "\r\n" + (string.IsNullOrEmpty(this.ValueFormat) ? value.ToString() : value.ToString(this.ValueFormat));
//设置为只显示值
//tbLabel.Text = value.ToString();
//设置为显示名称和值
tbLabel.Text = label + "\r\n" + string.Format("{0:#%}", value / sum);
if (mAngle <= 90)
{
tbLabel.HorizontalAlignment = HorizontalAlignment.Left;
tbLabel.VerticalAlignment = VerticalAlignment.Bottom;
tbLabel.Margin = new Thickness(lX + LabelSpace, 0, 0, this.ActualHeight - lY + LabelSpace);
}
else
{
if (mAngle <= 180)
{
tbLabel.HorizontalAlignment = HorizontalAlignment.Left;
tbLabel.VerticalAlignment = VerticalAlignment.Top;
tbLabel.Margin = new Thickness(lX + LabelSpace, lY + LabelSpace, 0, 0);
}
else
{
if (mAngle <= 270)
{
tbLabel.HorizontalAlignment = HorizontalAlignment.Right;
tbLabel.VerticalAlignment = VerticalAlignment.Top;
tbLabel.Margin = new Thickness(0, lY + LabelSpace, this.ActualWidth - (ShowLegend ? LegendWidth : 0) - lX + LabelSpace, 0);
}
else
{
tbLabel.HorizontalAlignment = HorizontalAlignment.Right;
tbLabel.VerticalAlignment = VerticalAlignment.Bottom;
tbLabel.Margin = new Thickness(0, 0, this.ActualWidth - (ShowLegend ? LegendWidth : 0) - lX + LabelSpace, this.ActualHeight - lY + LabelSpace);
}
}
}
gChart.Children.Add(tbLabel);
}
startPoint = curPoint;
startAngle = cAngle;
}
}
}
#endregion
}