WPF开发者QQ群: 340500857 | 微信群 -> 进入公众号主页 加入组织
有小伙伴提出需要实现统计图。
由于在WPF中没有现成的统计图控件,所以我们自己实现一个。
PS:有更好的方式欢迎推荐。
01
—
代码如下
一、创建 BasicBarChart.cs 菜单继承 Control代码如下。
BasicBarChart.cs实现思路如下
1、SeriesArray :存放展示集合 。
2、重写OnRender 。
3、先绘制X轴线。
4、调用GetFormattedText()绘制底部类别。
5、调用GetFormattedText()绘制左侧标尺。
6、DrawingContext绘制Line的时候会发虚,以下方法可以避免
var d = Pen.Thickness / 2;
var guidelines = new GuidelineSet(new[] { d }, new[] { d });
drawingContext.PushGuidelineSet(guidelines);
或者调用
SnapDrawingExtensions.DrawSnappedLinesBetweenPoints
避免画线发虚。
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;namespace WPFDevelopers.Controls
{public class BasicBarChart : Control{public IEnumerable<KeyValuePair<string, double>> SeriesArray{get { return (IEnumerable<KeyValuePair<string, double>>)GetValue(SeriesArrayProperty); }set { SetValue(SeriesArrayProperty, value); }}public static readonly DependencyProperty SeriesArrayProperty =DependencyProperty.Register("SeriesArray", typeof(IEnumerable<KeyValuePair<string, double>>), typeof(BasicBarChart), new UIPropertyMetadata(SeriesArrayChanged));private static void SeriesArrayChanged(DependencyObject d, DependencyPropertyChangedEventArgs e){BasicBarChart radarChart = d as BasicBarChart;if (e.NewValue != null)radarChart.InvalidateVisual();}static BasicBarChart(){DefaultStyleKeyProperty.OverrideMetadata(typeof(BasicBarChart), new FrameworkPropertyMetadata(typeof(BasicBarChart)));}protected override void OnRender(DrawingContext drawingContext){//base.OnRender(drawingContext);if (SeriesArray == null || SeriesArray.Count() == 0)return;SnapsToDevicePixels = true;UseLayoutRounding = true;var brushConverter = new BrushConverter();var myPen = new Pen{Thickness = 1,Brush = (Brush)brushConverter.ConvertFromString("#6E7079")};myPen.Freeze();//var d = myPen.Thickness / 2;//var guidelines = new GuidelineSet(new[] { d }, new[] { d });//drawingContext.PushGuidelineSet(guidelines);var h = this.ActualHeight / 2 + 160;var w = this.ActualWidth / 2;var startX = w / 3;var width = SeriesArray.Count() * 120 + startX;//drawingContext.DrawLine(myPen, new Point(startX, h), new Point(width, h));var stratNum = 0;SnapDrawingExtensions.DrawSnappedLinesBetweenPoints(drawingContext,myPen,myPen.Thickness, new Point(startX, h), new Point(width, h));var formattedText = GetFormattedText(stratNum.ToString());drawingContext.DrawText(formattedText, new Point(startX - formattedText.Width * 2 - 10, h - formattedText.Height / 2));var x = startX;//var y = h + d;var y = h + myPen.Thickness;var points = new List<Point>();var rectBrush = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#5470C6"));for (int i = 0; i < SeriesArray.Count() + 1; i++){//drawingContext.DrawLine(myPen, new Point(x, y), new Point(x, y + 4));points.Add(new Point(x, y));points.Add(new Point(x, y + 4));x = x + 120;}SnapDrawingExtensions.DrawSnappedLinesBetweenPoints(drawingContext, myPen, myPen.Thickness, points.ToArray());var xAxisPen = new Pen{Thickness = 1,Brush = (Brush)brushConverter.ConvertFromString("#E0E6F1")};xAxisPen.Freeze();var xAxis = h - 80;int max = Convert.ToInt32(SeriesArray.Max(kvp => kvp.Value));max = (max / 50 + (max % 50 == 0 ? 0 : 1)) * 50 / 50;int min = Convert.ToInt32(SeriesArray.Min(kvp => kvp.Value));points.Clear();for (int i = 0; i < max; i++){//drawingContext.DrawLine(xAxisPen, new Point(startX, xAxis), new Point(width, xAxis));points.Add(new Point(startX, xAxis));points.Add(new Point(width, xAxis));stratNum += 50;formattedText = GetFormattedText(stratNum.ToString());drawingContext.DrawText(formattedText, new Point(startX - formattedText.Width - 10, xAxis - formattedText.Height / 2));xAxis = xAxis - 80;}SnapDrawingExtensions.DrawSnappedLinesBetweenPoints(drawingContext, xAxisPen, xAxisPen.Thickness, points.ToArray());x = startX;var rectWidth = 85;var rectHeight = 0D;for (int i = 0; i < SeriesArray.Count(); i++){formattedText = GetFormattedText(SeriesArray.ToList()[i].Key);drawingContext.DrawText(formattedText, new Point(x + 120 / 2 - formattedText.Width / 2, y + 4));var _value = SeriesArray.ToList()[i].Value;//rectHeight = _value * 200;rectHeight = (_value - 0) / (stratNum - 0) * (80 * max);//rectHeight = (stratNum - _value) / 100 * stratNum;drawingContext.DrawRectangle(rectBrush, null, new Rect(x + (120 - 85) / 2, h - rectHeight, rectWidth, rectHeight));x = x + 120;}}FormattedText GetFormattedText(string text){var brushConverter = new BrushConverter();return new FormattedText(text,CultureInfo.CurrentCulture,FlowDirection.LeftToRight,new Typeface(new FontFamily("Microsoft YaHei"), FontStyles.Normal, FontWeights.UltraLight, FontStretches.Normal),12, (Brush)brushConverter.ConvertFromString("#6E7079")){MaxLineCount = 1,TextAlignment = TextAlignment.Justify,Trimming = TextTrimming.CharacterEllipsis};}}public static class SnapDrawingExtensions{public static void DrawSnappedLinesBetweenPoints(this DrawingContext dc,Pen pen, double lineThickness, params Point[] points){var guidelineSet = new GuidelineSet();foreach (var point in points){guidelineSet.GuidelinesX.Add(point.X);guidelineSet.GuidelinesY.Add(point.Y);}var half = lineThickness / 2;points = points.Select(p => new Point(p.X + half, p.Y + half)).ToArray();dc.PushGuidelineSet(guidelineSet);for (var i = 0; i < points.Length - 1; i = i + 2){dc.DrawLine(pen, points[i], points[i + 1]);}dc.Pop();}}
}
二、创建BasicBarChartExample.xaml代码如下
<UserControl x:Class="WPFDevelopers.Samples.ExampleViews.BasicBarChartExample"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:WPFDevelopers.Samples.ExampleViews"xmlns:wpfdev="https://github.com/yanjinhuagood/WPFDevelopers"mc:Ignorable="d" d:DesignHeight="450" d:DesignWidth="800"><Grid Background="Gainsboro"><BorderHeight="500"Background="White"Margin="30,0"><Grid Margin="20,10"><Grid.RowDefinitions><RowDefinition Height="40" /><RowDefinition /><RowDefinition Height="auto" /></Grid.RowDefinitions><WrapPanel HorizontalAlignment="Right"><RectangleWidth="6"Height="26"Fill="Black" /><TextBlockPadding="10,0"FontSize="24"FontWeight="Black"Text="{Binding KeyBarChart, RelativeSource={RelativeSource AncestorType=local:BasicBarChartExample}}" /></WrapPanel><wpfdev:BasicBarChartGrid.Row="1"SeriesArray="{Binding SeriesModels, RelativeSource={RelativeSource AncestorType=local:BasicBarChartExample}}"/><ButtonGrid.Row="2"Width="200"VerticalAlignment="Bottom"Click="Button_Click"Content="刷新"Style="{StaticResource PrimaryButton}" /></Grid></Border></Grid>
</UserControl>
三、创建BasicBarChartExample.xaml.cs代码如下
/// <summary>/// BasicBarChartExample.xaml 的交互逻辑/// </summary>public partial class BasicBarChartExample : UserControl{public IEnumerable<KeyValuePair<string, double>> SeriesModels{get { return (IEnumerable<KeyValuePair<string, double>>)GetValue(SeriesModelsProperty); }set { SetValue(SeriesModelsProperty, value); }}public static readonly DependencyProperty SeriesModelsProperty =DependencyProperty.Register("SeriesModels", typeof(IEnumerable<KeyValuePair<string, double>>), typeof(BasicBarChartExample), new PropertyMetadata(null));Dictionary<string, IEnumerable<KeyValuePair<string, double>>> keyValues = new Dictionary<string, IEnumerable<KeyValuePair<string, double>>>();public string KeyBarChart{get { return (string)GetValue(KeyBarChartProperty); }set { SetValue(KeyBarChartProperty, value); }}public static readonly DependencyProperty KeyBarChartProperty =DependencyProperty.Register("KeyBarChart", typeof(string), typeof(BasicBarChartExample), new PropertyMetadata(null));private int _index = 0;public BasicBarChartExample(){InitializeComponent();var Models1 = new[]{new KeyValuePair<string, double>("Mon", 120),new KeyValuePair<string, double>("Tue", 130),new KeyValuePair<string, double>("Wed", 160),new KeyValuePair<string, double>("Thu", 140),new KeyValuePair<string, double>("Fri", 200) ,new KeyValuePair<string, double>("Sat", 80) ,new KeyValuePair<string, double>("Sun", 90) ,};keyValues.Add("到访数", Models1);var Models2 = new[]{new KeyValuePair<string, double>("蛐蛐", 120),new KeyValuePair<string, double>("常威", 170),new KeyValuePair<string, double>("来福", 30),new KeyValuePair<string, double>("包龙星", 200),new KeyValuePair<string, double>("包有为", 100) ,new KeyValuePair<string, double>("雷豹", 180) ,new KeyValuePair<string, double>("方唐镜", 90) ,};keyValues.Add("能力值", Models2);SeriesModels = keyValues.ToList()[0].Value;KeyBarChart = keyValues.ToList()[0].Key;}private void Button_Click(object sender, RoutedEventArgs e){_index++;if (_index >= keyValues.Count){_index = 0;}SeriesModels = keyValues.ToList()[_index].Value;KeyBarChart = keyValues.ToList()[_index].Key;}
02
—
效果预览
上一篇雷达图更新了
源码地址如下
github:https://github.com/yanjinhuagood/WPFDevelopers.git
gitee:https://gitee.com/yanjinhua/WPFDevelopers.git
WPF开发者QQ群: 340500857
blogs: https://www.cnblogs.com/yanjinhua
Github:https://github.com/yanjinhuagood
出处:https://www.cnblogs.com/yanjinhua
版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。
转载请著名作者 出处 https://github.com/yanjinhuagood
扫一扫关注我们,
更多知识早知道!
点击阅读原文可跳转至源代码