OxyPlot 图未在子网格中呈现
OxyPlot graph not rendering in child Grid
我正在使用 OxyPlot WPF 制作统计应用程序,用户在其中输入 class 限制和每个 class 的频率。然后您选择要显示的 4 个图形中的哪一个。然后图表会显示在那个白色框中(见下图)。
Statistics app GUI
在 MainWindow
构造函数中,我设置了 this.DataContext = this
。我有一个名为 "MyModel" 的 PlotModel
属性,它绑定到 XAML 代码中 PlotView
控件的模型 属性(<oxy:PlotView Model="{Binding MyModel}"/>
)。这个 PlotView
在一个叫做 "Graph" 的 Grid
里面,它在主 Grid
里面(它在我所有 xaml 代码的底部)。
因此,当单击 "Display" 按钮时,在其事件处理程序中,它将根据选中的单选按钮进入不同的 if 语句。在每个 if 语句的末尾,this.MyModel
被设置为在其中创建的 PlotModel
。我认为通过编写 this.MyModel = model
它应该显示图形但是当我测试它时,白色部分没有任何渲染
(查看下面的所有代码)。
我不确定这个问题是因为 this.MyModel= model
在子网格内还是存在绑定问题。
总的来说,我对 WPF 编程还比较陌生,如有任何帮助,我们将不胜感激。谢谢!
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;
}
}
}
快速修复你的代码
而是<oxy:PlotView Model="{Binding MyModel}"/>
使用 <oxy:PlotView x:Name="myPlot"/>
删除 public PlotModel MyModel { get; private set; }
并在创建后直接设置模型。
myPlot.Model=model;
P.S。如果您不知道它是如何工作的,请不要使用 Binding
我正在使用 OxyPlot WPF 制作统计应用程序,用户在其中输入 class 限制和每个 class 的频率。然后您选择要显示的 4 个图形中的哪一个。然后图表会显示在那个白色框中(见下图)。
Statistics app GUI
在 MainWindow
构造函数中,我设置了 this.DataContext = this
。我有一个名为 "MyModel" 的 PlotModel
属性,它绑定到 XAML 代码中 PlotView
控件的模型 属性(<oxy:PlotView Model="{Binding MyModel}"/>
)。这个 PlotView
在一个叫做 "Graph" 的 Grid
里面,它在主 Grid
里面(它在我所有 xaml 代码的底部)。
因此,当单击 "Display" 按钮时,在其事件处理程序中,它将根据选中的单选按钮进入不同的 if 语句。在每个 if 语句的末尾,this.MyModel
被设置为在其中创建的 PlotModel
。我认为通过编写 this.MyModel = model
它应该显示图形但是当我测试它时,白色部分没有任何渲染
(查看下面的所有代码)。
我不确定这个问题是因为 this.MyModel= model
在子网格内还是存在绑定问题。
总的来说,我对 WPF 编程还比较陌生,如有任何帮助,我们将不胜感激。谢谢!
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;
}
}
}
快速修复你的代码
而是<oxy:PlotView Model="{Binding MyModel}"/>
使用 <oxy:PlotView x:Name="myPlot"/>
删除 public PlotModel MyModel { get; private set; }
并在创建后直接设置模型。
myPlot.Model=model;
P.S。如果您不知道它是如何工作的,请不要使用 Binding