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;
}
}
}