从 ChartValues 中删除元素后值的计算不正确

Incorrect calculation of values after removing an element from ChartValues

我的应用程序通过给定的公式计算分数。每隔一小段时间,新点就会添加到图表中。使用滑块我可以调整这些点的值。

出于优化目的,开始从列表中删除不需要的点。但是删除后,当你移动滑块时,下一个点的值开始计算错误。

Before points deleting (gif)

After points deleting (gif)

如何解决这个问题?

Class:

using System.Windows;
using LiveCharts;
using LiveCharts.Wpf;
using LiveCharts.Defaults;
using System.Windows.Media;
using System.Threading.Tasks;
using System;
using System.Threading;

namespace TestChartApp
{
    public partial class MainWindow : Window
    {
        SeriesCollection series = new SeriesCollection();

        ChartValues<ObservableValue> observableValues = new ChartValues<ObservableValue>();

        LineSeries lineSeries = new LineSeries
        {
            Stroke = Brushes.Blue,
            Fill = Brushes.Transparent,
            PointGeometry = null
        };

        double currentStep = 0;

        public MainWindow()
        {
            InitializeComponent();

            lineSeries.Values = observableValues;

            series.Add(lineSeries);

            myChart.Series = series;
            myChart.DataTooltip = null;
            myChart.Hoverable = false;

            Task.Factory.StartNew(AddValues);
        }

        private void AddValues()
        {
            Application.Current.Dispatcher.Invoke(() =>
            {
                ObservableValue value = new ObservableValue(sAmplitude.Value * Math.Sin(2 * Math.PI * 0.25 * currentStep));
                currentStep += 0.06;

                observableValues.Add(value);

                if (observableValues.Count > 100)
                {
                    SetAxisLimits(observableValues.Count);
                }

                if (observableValues.Count > 150)
                {
                    observableValues.RemoveAt(0);
                }
            });

            Thread.Sleep(35);

            Task.Factory.StartNew(AddValues);
        }

        private void SetAxisLimits(double value)
        {
            Axis axis = myChart.AxisX[0];
            axis.MinValue += value - axis.MaxValue;
            axis.MaxValue = value;
        }

        private void ChangeObservableValues()
        {
            int j = 0;

            for (double i = 0.0; j < observableValues.Count; i += 0.06)
            {
                observableValues[j++].Value = sAmplitude.Value * Math.Sin(2 * Math.PI * 0.25 * i);
            }
        }

        private void sAmplitude_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            if (lineSeries.Values != null)
            {
                ChangeObservableValues();
            }
        }
    }
}

XAML:

<Window x:Class="TestChartApp.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:TestChartApp"
        xmlns:lvc="clr-namespace:LiveCharts.Wpf;assembly=LiveCharts.Wpf"
        mc:Ignorable="d"
        Title="MainWindow" Height="600" Width="800">
    <Grid>

        <Grid.RowDefinitions>
            <RowDefinition Height="0.8*"/>
            <RowDefinition Height="0.2*"/>
        </Grid.RowDefinitions>
        
        <lvc:CartesianChart x:Name="myChart" DisableAnimations="True">
            <lvc:CartesianChart.AxisX>
                <lvc:Axis MaxValue="100" MinValue="0" Labels="" Unit="1">
                    <lvc:Axis.Separator>
                        <lvc:Separator Step="20">
                            <lvc:Separator.Stroke>
                                <SolidColorBrush Color="Gray" />
                            </lvc:Separator.Stroke>
                        </lvc:Separator>
                    </lvc:Axis.Separator>
                </lvc:Axis>
            </lvc:CartesianChart.AxisX>
            <lvc:CartesianChart.AxisY>
                <lvc:Axis MaxValue="100" MinValue="-100" Labels="">
                    <lvc:Axis.Separator>
                        <lvc:Separator>
                            <lvc:Separator.Stroke>
                                <SolidColorBrush Color="Gray" />
                            </lvc:Separator.Stroke>
                        </lvc:Separator>
                    </lvc:Axis.Separator>
                </lvc:Axis>
            </lvc:CartesianChart.AxisY>
        </lvc:CartesianChart>


        <Grid Grid.Row="1">

            <Grid.ColumnDefinitions>
                <ColumnDefinition />
                <ColumnDefinition />
                <ColumnDefinition />
            </Grid.ColumnDefinitions>

            <Slider x:Name="sAmplitude" HorizontalAlignment="Stretch" Margin="30 30 30 0" Grid.Row="1" VerticalAlignment="Top" Maximum="100" Value="50" LargeChange="10" ValueChanged="sAmplitude_ValueChanged"/>
            
        </Grid>

    </Grid>
</Window>

您似乎在更新旧数据时计算了错误的值。
ChangeObservableValues 正在计算自己的 currentSteps 值,总是从 0 开始,这是错误的,因为当前数据点的原始值更大:

originalCurrentStepsOfCurrentDataPoint = absoluteCurrentDataPointPosition * 0.06.

为了更容易重构并消除潜在的错误源,值 0.06 应该是常量字段或 read-only 属性.

private const double Step = 0.06;

private void ChangeObservableValues()
{
  // Because the collection only contains the latest 150 values,
  // we can calculate the absolute position using the collection's Count
  var restoredCurrentStep = 
    this.currentStep - this.observableValues.Count * MainWindow.Step;

  for (int index = 0; index < observableValues.Count; index++)
  {
    observableValues[index].Value = 
      sAmplitude.Value * Math.Sin(2 * Math.PI * 0.25 * restoredCurrentStep);
    restoredCurrentStep += MainWindow.Step;
  }
}