You were on the right path to resolve it, I used your code as guideline.

So, 1st here is the code that provide your desired result,
This goes to the MainWindow xaml:
<Window x:Class="WpfApp2.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:WpfApp2"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="30" />
<RowDefinition Height="20" />
<RowDefinition />
</Grid.RowDefinitions>
<Button Grid.Row="0" Content="Button" HorizontalAlignment="Left" Click="GenerateGraphBtn_Click" />
<Canvas Grid.Row="2" x:Name="GrpahArea" Margin="40" />
</Grid>
</Window>
And this goes into the code-behind of the MainWindow
using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Shapes;
namespace WpfApp2
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private Point[] GenerateGraphPoints(int minimumX, int maximumX, int minimumY, int maximumY)
{
var result = new List<Point>();
var rnd = new Random();
for (var x = minimumX; x < maximumX; x++)
result.Add(new Point(x, rnd.Next(minimumY, maximumY)));
return result.ToArray();
}
private void PlotXAxes(Panel drawArea, int minimumX, int maximumX, int step, int miniLineExtent)
{
var geometryGroup = new GeometryGroup();
var axePositionY = drawArea.ActualHeight;
geometryGroup.Children.Add(new LineGeometry(new Point(0, axePositionY), new Point(drawArea.ActualWidth, axePositionY)));
var factorX = drawArea.ActualWidth / (maximumX - minimumX);
for (var i = minimumX; i < maximumX; i++)
if (i % step == 0)
{
geometryGroup.Children.Add(new LineGeometry(
new Point(i * factorX, axePositionY - miniLineExtent),
new Point(i * factorX, axePositionY + miniLineExtent)));
drawArea.Children.Add(new Label
{
Margin = new Thickness(i*factorX, axePositionY + miniLineExtent, 0, 0),
Content = i,
Foreground = Brushes.Black
});
}
var path = new Path
{
StrokeThickness = 2,
Stroke = Brushes.DarkRed,
Data = geometryGroup
};
drawArea.Children.Add(path);
}
private void PlotYAxes(Panel drawArea, int minimumY, int maximumY, int step, int miniLineExtent)
{
var labelSize = new Size(30, 26);
var geometryGroup = new GeometryGroup();
var axePositionX = 0;
geometryGroup.Children.Add(new LineGeometry(new Point(axePositionX, 0), new Point(axePositionX, drawArea.ActualHeight)));
var factorY = drawArea.ActualHeight / (maximumY - minimumY);
for (var i = minimumY; i < maximumY; i++)
if (i % step == 0)
{
geometryGroup.Children.Add(new LineGeometry(
new Point(axePositionX - miniLineExtent, (maximumY-i) * factorY),
new Point(axePositionX + miniLineExtent, (maximumY-i) * factorY)));
drawArea.Children.Add(new Label
{
Width = labelSize.Width,
Height = labelSize.Height,
Margin = new Thickness(
axePositionX - miniLineExtent - labelSize.Width,
(maximumY - i) * factorY - (labelSize.Height / 2), 0, 0),
Content = i,
Foreground = Brushes.Black
});
}
var path = new Path
{
StrokeThickness = 2,
Stroke = Brushes.DarkRed,
Data = geometryGroup
};
drawArea.Children.Add(path);
}
private void PlotGraph(Point[] points, Panel drawArea, int minimumX, int maximumX, int minimumY, int maximumY)
{
var factorX = drawArea.ActualWidth / (maximumX-minimumX);
var factorY = drawArea.ActualHeight / (maximumY-minimumY);
for (var i = 0; i < points.Length; i++)
{
points[i].X *= factorX;
//points[i].Y *= factorY;
points[i].Y = (maximumY - points[i].Y) * factorY; //since zero of Y should be in bottom we "swap" the Y value.
}
Polyline polyline = new Polyline();
polyline.StrokeThickness = 2;
polyline.Stroke = Brushes.Blue;
polyline.Points = new PointCollection(points);
drawArea.Children.Add(polyline);
}
private void GenerateGraphBtn_Click(object sender, RoutedEventArgs e)
{
//Step 1: define the data limits and generate the data, this has nothing to do with the view.
const int xmin = 0, xmax = 12;
const int ymin = 0, ymax = 800;
var graphPoints = GenerateGraphPoints(xmin, xmax, ymin, ymax);
//Step 2: Draw yAxes
PlotYAxes(GrpahArea, ymin, ymax, 100, 2);
//Step 3: Draw xAxes
PlotXAxes(GrpahArea, xmin, xmax, 1, 2);
//Step 4: Plot Grpah
var plotPoints = new Point[graphPoints.Length]; //graphPoints is our model, we usually wish to keep the original value of model.
graphPoints.CopyTo(plotPoints,0); //plotPoints is what we going to scale and adjust to the view.
PlotGraph(plotPoints, GrpahArea, xmin, xmax, ymin, ymax);
}
}
}
Now to the 2nd part of my answer, Building a graph component is not that simple task, mostly since graphs are usually developed as generic to many applications, so the amount of allowed customization need to be enormous, this is why the others rightfully directed you to a ready library.
Also, the code I provided you in the answer is not MVVM style, it is very near to the code you provided. This is since writing that in MVVM-style will require creating a set of view model classes and bind them to the view, considering the customizations, it is quite an effort compared to what you asked to resolve.
Nevertheless I hope the code provided can help you do whatever you wanted.
Update, adding labels:
using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Shapes;
namespace WpfApp2
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private Point[] GenerateGraphPoints(int minimumX, int maximumX, int minimumY, int maximumY)
{
var result = new List<Point>();
var rnd = new Random();
for (var x = minimumX; x < maximumX; x++)
result.Add(new Point(x, rnd.Next(minimumY, maximumY)));
return result.ToArray();
}
private void PlotXAxes(Panel drawArea, int minimumX, int maximumX, int step, int miniLineExtent, string title)
{
var geometryGroup = new GeometryGroup();
var axePositionY = drawArea.ActualHeight;
geometryGroup.Children.Add(new LineGeometry(new Point(0, axePositionY), new Point(drawArea.ActualWidth, axePositionY)));
var factorX = drawArea.ActualWidth / (maximumX - minimumX);
for (var i = minimumX; i < maximumX; i++)
if (i % step == 0)
{
geometryGroup.Children.Add(new LineGeometry(
new Point(i * factorX, axePositionY - miniLineExtent),
new Point(i * factorX, axePositionY + miniLineExtent)));
drawArea.Children.Add(new Label
{
Margin = new Thickness(i*factorX, axePositionY + miniLineExtent, 0, 0),
Content = i,
Foreground = Brushes.Black
});
}
var path = new Path
{
StrokeThickness = 2,
Stroke = Brushes.DarkRed,
Data = geometryGroup
};
drawArea.Children.Add(path);
var titleLabel = new Label
{
Margin = new Thickness(drawArea.ActualWidth - 50, drawArea.ActualHeight - 20, 0, 0),
Content = title
};
drawArea.Children.Add(titleLabel);
}
private void PlotYAxes(Panel drawArea, int minimumY, int maximumY, int step, int miniLineExtent, string title)
{
var labelSize = new Size(30, 26);
var geometryGroup = new GeometryGroup();
var axePositionX = 0;
geometryGroup.Children.Add(new LineGeometry(new Point(axePositionX, 0), new Point(axePositionX, drawArea.ActualHeight)));
var factorY = drawArea.ActualHeight / (maximumY - minimumY);
for (var i = minimumY; i < maximumY; i++)
if (i % step == 0)
{
geometryGroup.Children.Add(new LineGeometry(
new Point(axePositionX - miniLineExtent, (maximumY-i) * factorY),
new Point(axePositionX + miniLineExtent, (maximumY-i) * factorY)));
drawArea.Children.Add(new Label
{
Width = labelSize.Width,
Height = labelSize.Height,
Margin = new Thickness(
axePositionX - miniLineExtent - labelSize.Width,
(maximumY - i) * factorY - (labelSize.Height / 2), 0, 0),
Content = i,
Foreground = Brushes.Black
});
}
var path = new Path
{
StrokeThickness = 2,
Stroke = Brushes.DarkRed,
Data = geometryGroup
};
drawArea.Children.Add(path);
var titleLabel = new Label
{
Margin = new Thickness(0, 0, 0, 0),
Content = title
};
drawArea.Children.Add(titleLabel);
}
private void PlotGraph(Point[] points, Panel drawArea, int minimumX, int maximumX, int minimumY, int maximumY)
{
var factorX = drawArea.ActualWidth / (maximumX-minimumX);
var factorY = drawArea.ActualHeight / (maximumY-minimumY);
for (var i = 0; i < points.Length; i++)
{
points[i].X *= factorX;
//points[i].Y *= factorY;
points[i].Y = (maximumY - points[i].Y) * factorY; //since zero of Y should be in bottom we "swap" the Y value.
}
Polyline polyline = new Polyline();
polyline.StrokeThickness = 2;
polyline.Stroke = Brushes.Blue;
polyline.Points = new PointCollection(points);
drawArea.Children.Add(polyline);
}
private void GenerateGraphBtn_Click(object sender, RoutedEventArgs e)
{
//Step 1: define the data limits and generate the data, this has nothing to do with the view.
const int xmin = 0, xmax = 12;
const int ymin = 0, ymax = 800;
var graphPoints = GenerateGraphPoints(xmin, xmax, ymin, ymax);
GrpahArea.Children.Add(new Label
{
Content = "Profits over months",
Margin = new Thickness(GrpahArea.ActualWidth / 2 - 100, -50, 0, 0)
});
//Step 2: Draw yAxes
PlotYAxes(GrpahArea, ymin, ymax, 100, 2, "Profits");
//Step 3: Draw xAxes
PlotXAxes(GrpahArea, xmin, xmax, 1, 2, "Months");
//Step 4: Plot Grpah
var plotPoints = new Point[graphPoints.Length]; //graphPoints is our model, we usually wish to keep the original value of model.
graphPoints.CopyTo(plotPoints,0); //plotPoints is what we going to scale and adjust to the view.
PlotGraph(plotPoints, GrpahArea, xmin, xmax, ymin, ymax);
}
}
}
marginis more then twice thestepvalue used in your code.