I'm making a statistics application using OxyPlot WPF where the user inputs the class limits and the frequencies for each class. Then you chose which of the 4 graphs you want displayed. Then the graph gets displayed in that white box (see image below).
In the MainWindow
constructor, I set the this.DataContext = this
. I have a PlotModel
property called "MyModel" which is binded to the the Model property of the PlotView
control in the XAML code ( <oxy:PlotView Model="{Binding MyModel}"/>
) . This PlotView
is inside a Grid
called "Graph" which is inside the main Grid
(it's at the bottom of all my xaml code).
So when the "Display" button is clicked, inside it's event handler, it'll go into a different if statement based on which radio button is checked. At the end of each if statement, this.MyModel
gets set to the PlotModel
that was created inside it. I think by writing this.MyModel = model
it's supposed to display the graph but when i tested it, nothing gets rendered in the white part
(see all code below).
I'm not sure if this problem is because the this.MyModel= model
is inside a child grid or if there's binding issues.
I'm relatively new to WPF programming in general and any help would be appreciated. Thanks!
MainWindow.xaml :
<Window
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:StatsApp"
xmlns:diag="clr-namespace:System.Diagnostics;assembly=WindowsBase"
xmlns:oxy="http://oxyplot.org/wpf"
xmlns:Properties="clr-namespace:StatsApp.Properties" x:Class="StatsApp.MainWindow"
mc:Ignorable="d"
Title="Frequency Distribution Graph Generator" Height="450" Width="800">
<Grid Background="Gray">
<Grid x:Name="Graph" HorizontalAlignment="Left" Height="306" Margin="340,39,0,0" VerticalAlignment="Top" Width="421">
<oxy:PlotView Model="{Binding MyModel}"/>
</Grid>
<!-- I left out all the unnecessary textboxes and buttons ..... -->
</Grid>
MainWindow.cs :
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.DataContext = this;
}
//private bool isfirstclick = true;
public PlotModel MyModel { get; private set; }
private void DisplayBtn_Click(object sender, RoutedEventArgs e)
{
// ---------------Retrieving Input START----------------
TextBox[] lowerLimitsTxtBoxes =
{
Lower1TxtBox,
Lower2TxtBox,
Lower3TxtBox,
Lower4TxtBox,
Lower5TxtBox,
Lower6TxtBox,
Lower7TxtBox,
Lower8TxtBox
};
TextBox[] upperLimitsTxtBoxes =
{
Upper1TxtBox,
Upper2TxtBox,
Upper3TxtBox,
Upper4TxtBox,
Upper5TxtBox,
Upper6TxtBox,
Upper7TxtBox,
Upper8TxtBox
};
TextBox[] freqsTxtBoxes =
{
Freq1TxtBox,
Freq2TxtBox,
Freq3TxtBox,
Freq4TxtBox,
Freq5TxtBox,
Freq6TxtBox,
Freq7TxtBox,
Freq8TxtBox
};
double[] lowerLimits = new double[8];
for (int i = 0; i < lowerLimits.Length; i++)
{
if (Double.TryParse(lowerLimitsTxtBoxes[i].Text, out double lower))
{
lowerLimits[i] = lower;
}
else
{
lowerLimits[i] = -1;
}
}
double[] upperLimits = new double[8];
for (int i = 0; i < upperLimits.Length; i++)
{
if (Double.TryParse(upperLimitsTxtBoxes[i].Text, out double upper))
{
upperLimits[i] = upper;
}
else
{
upperLimits[i] = -1;
}
}
//IMPORTANT -> The array of frequencies
int[] freqs = new int[8];
for (int i = 0; i < freqs.Length; i++)
{
if (Int32.TryParse(freqsTxtBoxes[i].Text, out int freq))
{
freqs[i] = freq;
}
else
{
freqs[i] = -1;
}
}
int numClasses = 0;
for (int i = 0; lowerLimits[i] != -1 && i < 8; i++)
{
numClasses++;
}
if (numClasses < 2)
{
throw new ArgumentException("Must use at least 2 classes");
}
//IMPORTANT -> The class marks array: double
double[] classMarks = new double[numClasses];
for (int i = 0; i < classMarks.Length; i++)
{
classMarks[i] = (lowerLimits[i] + upperLimits[i]) / 2.0;
}
//IMPORTANT -> The class marks array: string
string[] classMarksString = new string[numClasses];
for (int i = 0; i < numClasses; i++)
{
classMarksString[i] = classMarks[i] + "";
}
//----------Retrieving Input END--------------------
if ((bool)ScatterRBtn.IsChecked)
{
var model = new PlotModel { Title = "Scatter Plot" };
var scatter = new ScatterSeries { MarkerType = MarkerType.Circle };
model.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Title = "Class Marks" });
model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, Title = "Frequency" });
for ( int i =0; i < numClasses; i++)
{
scatter.Points.Add(new ScatterPoint(classMarks[i], freqs[i]));
}
model.Series.Add(scatter);
//This doesn't update the graph even though I binded it in XAML code
this.MyModel = model;
}
else if ((bool)RelativeFqRBtn.IsChecked)
{
var model = new PlotModel { Title = "Relative Frequency Polygon" };
model.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Maximum = 1, Title = "Class Marks" });
model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, Title = "Frequency (%)" });
var relativeFQ = new LineSeries();
int frequencyTotal = 0;
for (int i=0; i < 8 && freqs[i] != -1 ; i++)
{
frequencyTotal += freqs[i];
}
for (int i = 0; i < numClasses; i++)
{
relativeFQ.Points.Add(new DataPoint(classMarks[i], freqs[i]/frequencyTotal ));
}
model.Series.Add(relativeFQ);
//This doesn't update the graph even though I binded it in XAML code
this.MyModel = model;
}
else if ((bool)CummuFqRBtn.IsChecked)
{
var model = new PlotModel { Title = "Cummulative Frequency Polygon" };
model.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Title= "Frequency" });
model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, Title ="Class Boundaries" });
var cummulativeFQ = new LineSeries();
double[] classBoundaries = new double[numClasses + 1];
double midpointDistance = (lowerLimits[1] - upperLimits[0]) / 2;
classBoundaries[0] = lowerLimits[0] - midpointDistance;
for (int i = 0; i < numClasses; i++)
{
classBoundaries[i + 1] = upperLimits[i] + midpointDistance;
}
cummulativeFQ.Points.Add(new DataPoint(classBoundaries[0], 0));
for (int i = 0; i< numClasses ; i++)
{
cummulativeFQ.Points.Add(new DataPoint(classBoundaries[i+1], freqs[i]));
}
model.Series.Add(cummulativeFQ);
//This doesn't update the graph even though I binded it in XAML code
this.MyModel = model;
}
else
{
var model = new PlotModel { Title = "Histogram" };
model.Axes.Add(new LinearAxis { Title = "Frequency", Position = AxisPosition.Left });
model.Axes.Add(new CategoryAxis
{
Title = "Class Marks",
ItemsSource = classMarksString
});
var histogram = new ColumnSeries();
model.Series.Add(histogram);
for (int i = 0; i < numClasses; i++)
{
histogram.Items.Add(new ColumnItem(freqs[i]));
}
//This doesn't update the graph even though I binded it in XAML code
this.MyModel = model;
}
}
}
Fast fix for you code
Instead <oxy:PlotView Model="{Binding MyModel}"/>
use <oxy:PlotView x:Name="myPlot"/>
Remove public PlotModel MyModel { get; private set; }
and set Model directly after you created it.
myPlot.Model=model;
P.S. Don't use Binding if you don't know how it works