Search code examples
c#wpflivecharts

Why is the chart not updating


I'm using C# library LiveCharts.wpf's CartesianChart to make a chart in a wpf application. The Chart should be updated in Real-Time and I don't understand why it isn't working.

Here is my simple mainwindow, it makes a Graderview

<Window x:Class="WpfApp1.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:WpfApp1"
    mc:Ignorable="d"
    Title="MainWindow" Height="450" Width="800">
<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="13*" x:Name="LeftColoumn"/>
        <ColumnDefinition Width="12*" x:Name="RightColumn"/>
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition Height="12*" x:Name="UpperRow"/>
        <RowDefinition Height="12*" x:Name="LowerRow"/>
    </Grid.RowDefinitions>
    <local:GraderView Grid.ColumnSpan="1">

    </local:GraderView>
</Grid>

Here is the wpf usercontrol graderView.cs. In the constructor it asynchronously starts a simulation. As this simulation progresses the event handler OnUpdateChartView gets called whenever new values are available.

public partial class GraderView : UserControl
{
    public ChartValues<int> GraderOutputCount { get; set; }
    public string[] GraderLabels { get; set; }
    public Grader Grader { get; set; }        

    public GraderView()
    {
        InitializeComponent();
        GraderOutputCount = new ChartValues<int>() { 1, 2, 3 };
        GraderLabels = new string[20];
        Simulator simulator = new Simulator();
        simulator.Simulate();
        Grader = simulator.Grader;
        Grader.UpdateChartView += OnUpdateChartView;
        DataContext = this;
    }
    //Event handler
    void OnUpdateChartView(object sender, EventArgs e)
    {
        Trace.WriteLine("OnUpdateChartView got called");
        GraderOutputCount = new ChartValues<int>(Grader.SortedOutputConveyors.Select(x => x.Item2.Count));
        GraderLabels = Grader.SortedOutputConveyors.Select(x => x.Item1).ToArray();
        for (int i = 0; i < GraderLabels.Length; i++)
        {
            Trace.WriteLine($"label:{GraderLabels[i]} amount:{GraderOutputCount[i]}");
        }
    }
}

Because of the Trace.Writelines I was able to verify that the event handler does get called when the app is running. This is for example what appears in the output window:

OnUpdateChartView got called
label:9,5 - 10,5 amount:4
label:8,5 - 9,5 amount:7
label:7,5 - 8,5 amount:9
label:6,5 - 7,5 amount:10
label:5,5 - 6,5 amount:7
label:4,5 - 5,5 amount:8
label:3,5 - 4,5 amount:7
label:2,5 - 3,5 amount:8
label:1,5 - 2,5 amount:7
label:0,5 - 1,5 amount:6

Here is the xaml of this WPF usercontrol GraderView. The Bindings appear correct to me. Values to GraderOutputCount and labels to GraderLabels.

<UserControl x:Class="WpfApp1.GraderView"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         xmlns:local="clr-namespace:WpfApp1"
         xmlns:lvc="clr-namespace:LiveCharts.Wpf;assembly=LiveCharts.Wpf"
         mc:Ignorable="d" 
         d:DesignHeight="300" d:DesignWidth="300" d:DataContext="{d:DesignInstance local:GraderView}">
<Grid>
    <lvc:CartesianChart>
        <lvc:CartesianChart.Series>
            <lvc:ColumnSeries Title="Grader" Values="{Binding GraderOutputCount}"/>
        </lvc:CartesianChart.Series>
        <lvc:CartesianChart.AxisX>
            <lvc:Axis Title="WeightClass" Labels="{Binding GraderLabels}"/>
        </lvc:CartesianChart.AxisX>
        <lvc:CartesianChart.AxisY>
            <lvc:Axis Title="BoxCount" />
        </lvc:CartesianChart.AxisY>
    </lvc:CartesianChart>
</Grid>

My expected result was to first get the 1, 2, 3 that I put in the constructor of the graderview and then as the simulation progresses the chart would update automatically to the newer values in GraderOutputCount and Graderlabels. This is not what actually happens. The chart just doesn't update at all. Can anybody tell me what I am doing wrong here? Thanks in advance

What it looks like


Solution

  • I have found why the problem occured. I changed

    GraderOutputCount = new ChartValues<int>(Grader.SortedOutputConveyors.Select(x => x.Item2.Count));
    

    To

    GraderOutputCount.Clear();
    foreach(var num in Grader.SortedOutputConveyors.Select(x => x.Item2.Count))
    {
        GraderOutputCount.Add(num);
    }