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