亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

WPF實現(xiàn)繪制餅狀統(tǒng)計圖的示例代碼

 更新時間:2024年10月21日 10:28:20   作者:WPF開發(fā)者  
這篇文章主要為大家詳細(xì)介紹了如何使用WPF實現(xiàn)繪制簡單的餅狀統(tǒng)計圖,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下

WPF 實現(xiàn)餅狀統(tǒng)計圖

  • 框架支持.NET4 至 .NET8;
  • Visual Studio 2022;

ChartPie 詳解

新增依賴屬性 Datas 存儲餅圖的數(shù)據(jù),當(dāng)數(shù)據(jù)發(fā)生更改時觸發(fā)控件的重繪。

構(gòu)造初始化顏色組 (vibrantColors) 為了區(qū)分每個扇形區(qū)顯示不同的顏色。

繪制餅圖

var drawingPen = CreatePen(2);
var boldDrawingPen = CreatePen(4);
var pieWidth = ActualWidth > ActualHeight ? ActualHeight : ActualWidth;
var pieHeight = ActualWidth > ActualHeight ? ActualHeight : ActualWidth;
centerX = pieWidth / 2;
centerY = pieHeight / 2;
radius = ActualWidth > ActualHeight ? ActualHeight / 2 : ActualWidth / 2;
  • 計算餅圖的寬度和高度,以確保餅圖是圓形的。
  • 計算圓心與半徑。

繪制每個扇形

var angle = 0d;
var prevAngle = 0d;
var sum = Datas.Select(ser => ser.Value).Sum();
var index = 0;
var isFirst = false;
foreach (var item in Datas)
{
    // 計算起始和結(jié)束角度
    var arcStartX = radius * Math.Cos(angle * Math.PI / 180) + centerX;
    var arcStartY = radius * Math.Sin(angle * Math.PI / 180) + centerY;
    angle = item.Value / sum * 360 + prevAngle;
    var arcEndX = 0d;
    var arcEndY = 0d;
    if (Datas.Count() == 1 && angle == 360)
    {
        isFirst = true;
        arcEndX = centerX + Math.Cos(359.99999 * Math.PI / 180) * radius;
        arcEndY = radius * Math.Sin(359.99999 * Math.PI / 180) + centerY;
    }
    else
    {
        arcEndX = centerX + Math.Cos(angle * Math.PI / 180) * radius;
        arcEndY = radius * Math.Sin(angle * Math.PI / 180) + centerY;
    }

    var startPoint = new Point(arcStartX, arcStartY);
    var line1Segment = new LineSegment(startPoint, false);
    var isLargeArc = item.Value / sum > 0.5;
    var arcSegment = new ArcSegment
    {
        Size = new Size(radius, radius),
        Point = new Point(arcEndX, arcEndY),
        SweepDirection = SweepDirection.Clockwise,
        IsLargeArc = isLargeArc
    };
    var center = new Point(centerX, centerY);
    var line2Segment = new LineSegment(center, false);
    var pathGeometry = new PathGeometry(new[]
    {
        new PathFigure(center, new List<PathSegment>
        {
            line1Segment,
            arcSegment,
            line2Segment
        }, true)
    });

    pathGeometries.Add(pathGeometry,
        $"{item.Key} : {item.Value.FormatNumber()}");

    var backgroupBrush = new SolidColorBrush
    {
        Color = vibrantColors[
            index >= vibrantColors.Length
                ? index % vibrantColors.Length
                : index]
    };
    backgroupBrush.Freeze();
    drawingContext.DrawGeometry(backgroupBrush, null, pathGeometry);

    index++;
    if (!isFirst)
    {
        if (index == 1)
            drawingContext.DrawLine(boldDrawingPen, center, startPoint);
        else
            drawingContext.DrawLine(drawingPen, center, startPoint);
    }
    prevAngle = angle;
}
  • 初始化角度 angleprevAngle,計算數(shù)據(jù)總和(sum)。
  • 循環(huán) Datas 集合,計算每條數(shù)據(jù)所需占的扇形區(qū)的起始角度和結(jié)束的角度。
  • 如果只有一條數(shù)據(jù)那么角度為 360度,然后繪制圓形。
  • 使用 ArcSegment 繪制圓形的弧度,連接圓心和扇形區(qū)邊緣。
  • 將生成的 PathGeometry 添加到 pathGeometries 中,并繪制每個的扇形區(qū)。
  • 繪制每個扇形區(qū)的邊框,根據(jù)索引設(shè)置畫筆的寬度用于邊框。
  • 更新 prevAngle 以用于計算下一個扇形區(qū)的角度。

1)新增 ChartPie.cs 代碼如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Effects;
using System.Windows.Shapes;
using WPFDevelopers.Core;

namespace WPFDevelopers.Controls
{
    public class ChartPie : Control
    {
        public static readonly DependencyProperty DatasProperty =
            DependencyProperty.Register("Datas", typeof(IEnumerable<KeyValuePair<string, double>>),
                typeof(ChartPie), new UIPropertyMetadata(DatasChanged));

        private Border _border;
        private Ellipse _ellipse;
        private KeyValuePair<PathGeometry, string> _lastItem;
        private Popup _popup;
        private StackPanel _stackPanel;
        private TextBlock _textBlock;
        private double centerX, centerY, radius;
        private bool isPopupOpen;
        private readonly Dictionary<PathGeometry, string> pathGeometries = new Dictionary<PathGeometry, string>();

        private readonly Color[] vibrantColors;

        public ChartPie()
        {
            vibrantColors = new[]
            {
                Color.FromArgb(255, 84, 112, 198),
                Color.FromArgb(255, 145, 204, 117),
                Color.FromArgb(255, 250, 200, 88),
                Color.FromArgb(255, 238, 102, 102),
                Color.FromArgb(255, 115, 192, 222),
                Color.FromArgb(255, 59, 162, 114),
                Color.FromArgb(255, 252, 132, 82),
                Color.FromArgb(255, 154, 96, 180),
                Color.FromArgb(255, 234, 124, 204)
            };
        }

        public IEnumerable<KeyValuePair<string, double>> Datas
        {
            get => (IEnumerable<KeyValuePair<string, double>>) GetValue(DatasProperty);
            set => SetValue(DatasProperty, value);
        }

        private static void DatasChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var ctrl = d as ChartPie;
            if (e.NewValue != null)
                ctrl.InvalidateVisual();
        }

        protected override void OnMouseMove(MouseEventArgs e)
        {
            base.OnMouseMove(e);
            if (Datas == null || Datas.Count() == 0 || isPopupOpen) return;
            if (_popup == null)
            {
                _popup = new Popup
                {
                    AllowsTransparency = true,
                    Placement = PlacementMode.MousePoint,
                    PlacementTarget = this,
                    StaysOpen = false
                };
                _popup.MouseMove += (y, j) =>
                {
                    var point = j.GetPosition(this);
                    if (isPopupOpen && _lastItem.Value != null)
                        if (!IsMouseOverGeometry(_lastItem.Key))
                        {
                            _popup.IsOpen = false;
                            isPopupOpen = false;
                            _lastItem = new KeyValuePair<PathGeometry, string>();
                        }
                };
                _popup.Closed += delegate { isPopupOpen = false; };

                _textBlock = new TextBlock
                {
                    HorizontalAlignment = HorizontalAlignment.Center,
                    VerticalAlignment = VerticalAlignment.Center,
                    Foreground = (Brush) Application.Current.TryFindResource("WD.WindowForegroundColorBrush"),
                    Padding = new Thickness(4, 0, 2, 0)
                };
                _ellipse = new Ellipse
                {
                    Width = 10,
                    Height = 10,
                    Stroke = Brushes.White
                };
                _stackPanel = new StackPanel {Orientation = Orientation.Horizontal};
                _stackPanel.Children.Add(_ellipse);
                _stackPanel.Children.Add(_textBlock);

                _border = new Border
                {
                    Child = _stackPanel,
                    Background = (Brush) Application.Current.TryFindResource("WD.ChartFillSolidColorBrush"),
                    Effect = Application.Current.TryFindResource("WD.PopupShadowDepth") as DropShadowEffect,
                    Margin = new Thickness(10),
                    CornerRadius = new CornerRadius(3),
                    Padding = new Thickness(6)
                };
                _popup.Child = _border;
            }

            var index = 0;
            foreach (var pathGeometry in pathGeometries)
            {
                if (IsMouseOverGeometry(pathGeometry.Key))
                {
                    isPopupOpen = true;
                    _ellipse.Fill = new SolidColorBrush
                    {
                        Color = vibrantColors[index >= vibrantColors.Length ? index % vibrantColors.Length : index]
                    };
                    _textBlock.Text = pathGeometry.Value;
                    _popup.IsOpen = true;
                    _lastItem = pathGeometry;
                    break;
                }

                index++;
            }
        }

        private bool IsMouseOverGeometry(PathGeometry pathGeometry)
        {
            var mousePosition = Mouse.GetPosition(this);
            return pathGeometry.FillContains(mousePosition);
        }

        protected override void OnRender(DrawingContext drawingContext)
        {
            base.OnRender(drawingContext);
            if (Datas == null || Datas.Count() == 0)
                return;
            SnapsToDevicePixels = true;
            UseLayoutRounding = true;
            pathGeometries.Clear();
            var drawingPen = CreatePen(2);
            var boldDrawingPen = CreatePen(4);
            var pieWidth = ActualWidth > ActualHeight ? ActualHeight : ActualWidth;
            var pieHeight = ActualWidth > ActualHeight ? ActualHeight : ActualWidth;
            centerX = pieWidth / 2;
            centerY = pieHeight / 2;
            radius = ActualWidth > ActualHeight ? ActualHeight / 2 : ActualWidth / 2;
            var angle = 0d;
            var prevAngle = 0d;
            var sum = Datas.Select(ser => ser.Value).Sum();
            var index = 0;
            var isFirst = false;
            foreach (var item in Datas)
            {
                var arcStartX = radius * Math.Cos(angle * Math.PI / 180) + centerX;
                var arcStartY = radius * Math.Sin(angle * Math.PI / 180) + centerY;
                angle = item.Value / sum * 360 + prevAngle;
                var arcEndX = 0d;
                var arcEndY = 0d;
                if (Datas.Count() == 1 && angle == 360)
                {
                    isFirst = true;
                    arcEndX = centerX + Math.Cos(359.99999 * Math.PI / 180) * radius;
                    arcEndY = radius * Math.Sin(359.99999 * Math.PI / 180) + centerY;
                }
                else
                {
                    arcEndX = centerX + Math.Cos(angle * Math.PI / 180) * radius;
                    arcEndY = radius * Math.Sin(angle * Math.PI / 180) + centerY;
                }

                var startPoint = new Point(arcStartX, arcStartY);
                var line1Segment = new LineSegment(startPoint, false);
                var isLargeArc = item.Value / sum > 0.5;
                var arcSegment = new ArcSegment();
                var size = new Size(radius, radius);
                var endPoint = new Point(arcEndX, arcEndY);
                arcSegment.Size = size;
                arcSegment.Point = endPoint;
                arcSegment.SweepDirection = SweepDirection.Clockwise;
                arcSegment.IsLargeArc = isLargeArc;
                var center = new Point(centerX, centerY);
                var line2Segment = new LineSegment(center, false);

                var pathGeometry = new PathGeometry(new[]
                {
                    new PathFigure(new Point(centerX, centerY), new List<PathSegment>
                    {
                        line1Segment,
                        arcSegment,
                        line2Segment
                    }, true)
                });
                pathGeometries.Add(pathGeometry,
                    $"{item.Key} : {item.Value.FormatNumber()}");
                var backgroupBrush = new SolidColorBrush
                {
                    Color = vibrantColors[
                        index >= vibrantColors.Length
                            ? index % vibrantColors.Length
                            : index]
                };
                backgroupBrush.Freeze();

                drawingContext.DrawGeometry(backgroupBrush, null, pathGeometry);
                index++;
                if (!isFirst)
                {
                    if (index == 1)
                        drawingContext.DrawLine(boldDrawingPen, center, startPoint);
                    else
                        drawingContext.DrawLine(drawingPen, center, startPoint);
                }

                prevAngle = angle;
            }
        }

        private Pen CreatePen(double thickness)
        {
            var pen = new Pen
            {
                Thickness = thickness,
                Brush = Brushes.White
            };
            pen.Freeze();
            return pen;
        }
    }
}

2)新增 ChartPieExample.xaml 示例代碼如下:

        <Grid Background="{DynamicResource WD.BackgroundSolidColorBrush}">
            <Grid.RowDefinitions>
                <RowDefinition />
                <RowDefinition Height="Auto" />
            </Grid.RowDefinitions>
            <ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
                <Border
                    Height="300"
                    Margin="30,0"
                    Background="{DynamicResource WD.BackgroundSolidColorBrush}">
                    <wd:ChartPie Datas="{Binding Datas, RelativeSource={RelativeSource AncestorType=local:ChartPieExample}}" />
                </Border>
            </ScrollViewer>
            <Button
                Grid.Row="1"
                Width="200"
                VerticalAlignment="Bottom"
                Click="Button_Click"
                Content="刷新"
                Style="{StaticResource WD.PrimaryButton}" />
        </Grid>

3)新增 ChartPieExample.xaml.cs 示例代碼如下:

using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;

namespace WPFDevelopers.Samples.ExampleViews
{
    /// <summary>
    /// ChartPieExample.xaml 的交互邏輯
    /// </summary>
    public partial class ChartPieExample : UserControl
    {
        public IEnumerable<KeyValuePair<string, double>> Datas
        {
            get { return (IEnumerable<KeyValuePair<string, double>>)GetValue(DatasProperty); }
            set { SetValue(DatasProperty, value); }
        }

        public static readonly DependencyProperty DatasProperty =
            DependencyProperty.Register("Datas", typeof(IEnumerable<KeyValuePair<string, double>>), typeof(ChartPieExample), new PropertyMetadata(null));

        private Dictionary<string, IEnumerable<KeyValuePair<string, double>>> keyValues = new Dictionary<string, IEnumerable<KeyValuePair<string, double>>>();
        private int _index = 0;
        public ChartPieExample()
        {
            InitializeComponent();
            var models1 = new[]
            {
                new KeyValuePair<string, double>("Mon", 120),
                new KeyValuePair<string, double>("Tue", 530),
                new KeyValuePair<string, double>("Wed", 1060),
                new KeyValuePair<string, double>("Thu", 140),
                new KeyValuePair<string, double>("Fri", 8000.123456) ,
                new KeyValuePair<string, double>("Sat", 200) ,
                new KeyValuePair<string, double>("Sun", 300) ,
            };
            var models2 = new[]
            {
                new KeyValuePair<string, double>("Bing", 120),
                new KeyValuePair<string, double>("Google", 170),
                new KeyValuePair<string, double>("Baidu", 30),
                new KeyValuePair<string, double>("Github", 200),
                new KeyValuePair<string, double>("Stack Overflow", 100) ,
                new KeyValuePair<string, double>("Runoob", 180) ,
                new KeyValuePair<string, double>("Open AI", 90) ,
                new KeyValuePair<string, double>("Open AI2", 93) ,
                new KeyValuePair<string, double>("Open AI3", 94) ,
                new KeyValuePair<string, double>("Open AI4", 95) ,
            };
            keyValues.Add("1", models1);
            keyValues.Add("2", models2);
            Datas = models1;
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            _index++;
            if (_index >= keyValues.Count)
            {
                _index = 0;
            }
            Datas = keyValues.ToList()[_index].Value;
        }
    }
}

效果圖

以上就是WPF實現(xiàn)繪制餅狀統(tǒng)計圖的示例代碼的詳細(xì)內(nèi)容,更多關(guān)于WPF繪制餅狀統(tǒng)計圖的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 使用c#開發(fā)公眾平臺自定義菜單功能

    使用c#開發(fā)公眾平臺自定義菜單功能

    微信公眾平臺服務(wù)號開放了自定義菜單API,本案例介紹C#開發(fā)微信公眾號自定義菜單功能。在此基礎(chǔ)上可以開發(fā)更完善的自定義菜單管理功能
    2014-01-01
  • c#窗體傳值用法實例詳解

    c#窗體傳值用法實例詳解

    這篇文章主要介紹了c#窗體傳值用法,以實例形式較為詳細(xì)的分析了C#窗體傳值的各種常用技巧,需要的朋友可以參考下
    2015-06-06
  • C#實現(xiàn)飛行棋游戲

    C#實現(xiàn)飛行棋游戲

    這篇文章主要為大家詳細(xì)介紹了C#實現(xiàn)飛行棋游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-07-07
  • WPF中MVVM模式的理解與實現(xiàn)

    WPF中MVVM模式的理解與實現(xiàn)

    MVVM是一種設(shè)計模式,特別適用于WPF(Windows Presentation Foundation)等XAML-based的應(yīng)用程序開發(fā),MVVM模式主要包含三個部分:Model(模型)、View(視圖)和ViewModel(視圖模型),本文給大家介紹了WPF中MVVM模式的理解與實現(xiàn),需要的朋友可以參考下
    2024-05-05
  • C# WindowsForm程序同時啟動多個窗口類

    C# WindowsForm程序同時啟動多個窗口類

    這篇文章主要為大家詳細(xì)介紹了C# WindowsForm程序同時啟動多個窗口類,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-06-06
  • C#生成sitemap站點地圖的方法

    C#生成sitemap站點地圖的方法

    C#生成sitemap站點地圖的方法,需要的朋友可以參考一下
    2013-04-04
  • 基于C#實現(xiàn)手機(jī)號碼歸屬地接口調(diào)用

    基于C#實現(xiàn)手機(jī)號碼歸屬地接口調(diào)用

    這篇文章主要介紹了基于C#實現(xiàn)手機(jī)號碼歸屬地接口調(diào)用的相關(guān)資料,需要的朋友可以參考下
    2016-02-02
  • Unity游戲開發(fā)中的設(shè)計模式之策略模式

    Unity游戲開發(fā)中的設(shè)計模式之策略模式

    策略模式是Unity游戲開發(fā)中常用的設(shè)計模式之一,用于封裝一系列算法或行為,并使這些算法或行為可以相互替換。通過策略模式,可以在運行時動態(tài)地選擇算法或行為,實現(xiàn)游戲中的多樣性和可擴(kuò)展性。常見的應(yīng)用包括AI行為、武器攻擊、移動方式等
    2023-05-05
  • C#使用游標(biāo)實現(xiàn)補(bǔ)間函數(shù)

    C#使用游標(biāo)實現(xiàn)補(bǔ)間函數(shù)

    這篇文章主要為大家詳細(xì)介紹了C#使用游標(biāo)實現(xiàn)補(bǔ)間函數(shù),文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-02-02
  • 淺談C#在網(wǎng)絡(luò)波動時防重復(fù)提交的方法

    淺談C#在網(wǎng)絡(luò)波動時防重復(fù)提交的方法

    這篇文章主要介紹了淺談C#在網(wǎng)絡(luò)波動時防重復(fù)提交的方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-04-04

最新評論