WPF draw graph

FredGrit發表於2024-04-12
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media;
using System.Windows.Shapes;

namespace WpfApp55
{
    class BarGraph:FrameworkElement
    {


        public double[] Values
        {
            get { return (double[])GetValue(ValuesProperty); }
            set { SetValue(ValuesProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Values.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ValuesProperty =
            DependencyProperty.Register("Values", typeof(double[]), typeof(BarGraph),
                new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.AffectsRender));
         

        public Brush Fill
        {
            get { return (Brush)GetValue(FillProperty); }
            set { SetValue(FillProperty, value); }
        }

        // Using a DependencyProperty as the backing store for MyProperty.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty FillProperty =
            Shape.FillProperty.AddOwner(typeof(BarGraph),
                new FrameworkPropertyMetadata(Brushes.White,
                    FrameworkPropertyMetadataOptions.AffectsRender));

         

        public Brush Stroke
        {
            get { return (Brush)GetValue(StrokeProperty); }
            set { SetValue(StrokeProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Stroke.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty StrokeProperty =
             Shape.StrokeProperty.AddOwner(typeof(BarGraph),
                 new FrameworkPropertyMetadata(Brushes.Black, FrameworkPropertyMetadataOptions.AffectsRender));
        public double StrokeThickness
        {
            get { return (double)GetValue(StrokeThicknessProperty); }
            set { SetValue(StrokeThicknessProperty, value); }
        }

        // Using a DependencyProperty as the backing store for StrokeThickness.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty StrokeThicknessProperty =
             Shape.StrokeThicknessProperty.AddOwner(typeof(BarGraph),
                 new FrameworkPropertyMetadata(1.0,
                     FrameworkPropertyMetadataOptions.AffectsRender));
         
        public bool ShowAverage
        {
            get { return (bool)GetValue(ShowAverageProperty); }
            set { SetValue(ShowAverageProperty, value); }
        }

        // Using a DependencyProperty as the backing store for ShowAverage.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ShowAverageProperty =
            DependencyProperty.Register("ShowAverage", typeof(bool), typeof(BarGraph),
                new FrameworkPropertyMetadata(false,
                    FrameworkPropertyMetadataOptions.AffectsRender));

        protected override void OnRender(DrawingContext drawingContext)
        {
             
            if(Values==null || Values.Length==0)
            {
                return;
            }

            double max = Values.Max();
            var pen = new Pen(Stroke, StrokeThickness);
            var barSize = ActualWidth / Values.Length;
            for(int i=0;i<Values.Length;i++) 
            {
                drawingContext.DrawRectangle(Fill, pen, new Rect(
                    new Point(i * barSize, ActualHeight - Values[i] * ActualHeight / max),
                    new Point((i + 1) * barSize, ActualHeight)));
            }

            if(ShowAverage)
            {
                var avg = ActualHeight - Values.Average() * ActualHeight / max;
                drawingContext.DrawLine(pen, new Point(0, avg), new Point(ActualWidth, avg));
            }
        }

         

    }
}




//xaml
<Window x:Class="WpfApp55.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApp55"
        mc:Ignorable="d" WindowState="Maximized"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <local:BarGraph x:Name="_graph" ShowAverage="True">
            <local:BarGraph.Fill>
                <LinearGradientBrush EndPoint="0,1">
                    <GradientStop Color="LightBlue" Offset="0"/>
                    <GradientStop Color="Blue" Offset="1"/>
                </LinearGradientBrush>
            </local:BarGraph.Fill>
        </local:BarGraph>
    </Grid>
</Window>



using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
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 WpfApp55
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            double[] values = { 45, 22, 104, 77, 18, 56, 39, 120 };
            _graph.Values = values;
        }

         
    }
}

相關文章