zoukankan      html  css  js  c++  java
  • WPF实现统计图(柱状图)

    WPF开发者QQ群: 340500857  | 微信群 -> 进入公众号主页 加入组织

    前言

        有小伙伴提出需要实现统计图。 

     

    由于在WPF中没有现成的统计图控件,所以我们自己实现一个。

    PS:有更好的方式欢迎推荐。

    代码如下

    一、创建 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">
            <Border
                Height="500"
                Background="White"
                Margin="30,0">
                <Grid Margin="20,10">
                    
                    <Grid.RowDefinitions>
                        <RowDefinition Height="40" />
                        <RowDefinition />
                        <RowDefinition Height="auto" />
                    </Grid.RowDefinitions>
                    <WrapPanel HorizontalAlignment="Right">
                        <Rectangle
                            Width="6"
                            Height="26"
                            Fill="Black" />
                        <TextBlock
                            Padding="10,0"
                            FontSize="24"
                            FontWeight="Black"
                            Text="{Binding KeyBarChart, RelativeSource={RelativeSource AncestorType=local:BasicBarChartExample}}" />
                    </WrapPanel>
                    <wpfdev:BasicBarChart
                         Grid.Row="1"
                        SeriesArray="{Binding SeriesModels, RelativeSource={RelativeSource AncestorType=local:BasicBarChartExample}}"/>
                    <Button
                        Grid.Row="2"
                        Width="200"
                        VerticalAlignment="Bottom"
                        Click="Button_Click"
                        Content="刷新"
                        Style="{StaticResource PrimaryButton}" />
                </Grid>
            </Border>
        </Grid>
    </UserControl>

    三、创建BasicBarChartExample.xaml.cs代码如下

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using System.Windows.Navigation;
    using System.Windows.Shapes;
    
    namespace WPFDevelopers.Samples.ExampleViews
    {
        /// <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;
            }
        }
    }

    效果预览

     

    更多教程欢迎关注微信公众号:加微信群限时

    微信群人数太多扫码进不来了,请添加个人微信邀请你(请标注理由)。(yanjinhuawechat)或(W_Feng_aiQ)

     

    WPF开发者QQ群: 340500857 

    blogs: https://www.cnblogs.com/yanjinhua

    源码Github:https://github.com/yanjinhuagood/WPFDevelopers.git

    gitee:https://gitee.com/yanjinhua/WPFDevelopers.git

     

  • 相关阅读:
    New starting
    Ubuntu中PyCharm中字体设置
    pyshp操作shapefile
    GIS的数学基础
    向mysql中插入Date类型的数据
    mysql多字段排序
    干掉命令行窗口下MySql乱码
    JavaWeb中读取文件资源的路径问题
    Java中9种IO的读取方式
    JavaIO 将数据写入到文件中去
  • 原文地址:https://www.cnblogs.com/yanjinhua/p/15490595.html
Copyright © 2011-2022 走看看