OxyPlot 图形不更新

OxyPlot graphic doesn't update

我正在使用 C#、.NET Framework 4.7 开发 WPF 应用程序。和 Oxyplot 1.0.

我正在尝试在运行时更新图形,但它没有任何作用。

我尝试使用 ObsevableCollectionInvalidateFlag 但没有成功。

这是XAML:

<oxy:Plot Title="{Binding Title}" InvalidateFlag="{Binding InvalidateFlag}">
    <oxy:Plot.Series>
        <oxy:LineSeries ItemsSource="{Binding BestFitness}"/>
        <oxy:LineSeries ItemsSource="{Binding WorstFitness}"/>
        <oxy:LineSeries ItemsSource="{Binding AverageFitness}"/>
    </oxy:Plot.Series>
</oxy:Plot>

这是视图模型:

public class MainViewModel : ObservableObject
{
    private int count;
    private int _invalidateFlag;

    public string Title { get; set; }

    public int InvalidateFlag
    {
        get { return _invalidateFlag; }
        set
        {
            _invalidateFlag = value;
            RaisePropertyChangedEvent("InvalidateFlag");
        }
    }

    public ObservableCollection<DataPoint> BestFitness { get; set; }
    public ObservableCollection<DataPoint> WorstFitness { get; set; }
    public ObservableCollection<DataPoint> AverageFitness { get; set; }

    public ICommand StartCommand
    {
        get { return new DelegateCommand(Start); }
    }

    public ICommand RefereshCommand
    {
        get { return new DelegateCommand(Refresh); }
    }

    public MainViewModel()
    {
        this.Title = "Example 2";
        this.BestFitness = new ObservableCollection<DataPoint>
        {
            new DataPoint(0, 4),
            new DataPoint(10, 13),
            new DataPoint(20, 15),
            new DataPoint(30, 16),
            new DataPoint(40, 12),
            new DataPoint(50, 12)
        };
    }

    private void Start()
    {
        Random rnd = new Random((int)DateTime.Now.Ticks);

        Program program = new Program(rnd);

        program.Algorithm.EvolutionEnded += Algorithm_EvolutionEnded;

        count = 0;
        this.BestFitness = new ObservableCollection<DataPoint>();
        this.WorstFitness = new ObservableCollection<DataPoint>();
        this.AverageFitness = new ObservableCollection<DataPoint>();

        Task.Run(() => program.Run(null));
    }

    private void Refresh()
    {
        this.BestFitness.Clear();
    }

    private void Algorithm_EvolutionEnded(object sender, EventArgs e)
    {
        EvolutionEndedEventArgs args = (EvolutionEndedEventArgs)e;

        BestFitness.Add(new DataPoint(count, args.BestFitness));
        WorstFitness.Add(new DataPoint(count, args.WorstFitness));
        AverageFitness.Add(new DataPoint(count, args.AverageFitness));

        InvalidateFlag++;
    }
}

我还需要做其他事情吗?

this.BestFitness = new ObservableCollection<DataPoint>();
...

您正在替换完整的 ItemsSource 情节。由于之后调用 RaisePropertyChangedEvent 没有通知视图,绑定的图将无法识别更改并且图不会更新它的点。

有两种可能的解决方案:

1.替换集合后通过调用 RaisePropertyChangedEvent 使用 INotifyPropertychanged。因此

public ObservableCollection<DataPoint> BestFitness { get; set; }

应该扩展到

private ObservableCollection<DataPoint> _BestFitness;
public ObservableCollection<DataPoint> BestFintess
{
    get
    {
        return _BestFitness;
    }
    private set
    {
        _BestFitness = value;
        RaisePropertyChangedEvent(nameof(BestFintess));
    }
}

2。不要替换整个 ObservableCollection。 只需清除现有集合并再次使用它们。这意味着使用

this.BestFitniss.Clear();

而不是

this.BestFitness = new ObservableCollection<DataPoint>();

两种解决方案都会通知有关更改的视图,并且绘图将在不使用 InvalidateFlag.

的情况下更新它的点

请注意,需要使用 UI 线程来更改 ObservableCollection 中的项目,如 this question 中所述。由于您正在使用其他线程来添加调用 UI like

的值
Application.Current.Dispatcher.BeginInvoke(() =>
    {
        BestFitness.Add(new DataPoint(count, args.BestFitness));
    });

为必填项。

我创建了这个小示例来展示如何在运行时更新图形。希望对您有所帮助!

视图模型:

using System;
using System.Timers;
using OxyPlot;
using OxyPlot.Series;

namespace WpfApp1
{
    public class MainViewModel
    {
        private LineSeries lineSeries;
        private int count;

        public MainViewModel()
        {
            this.MyModel = new PlotModel { Title = "Example 1" };
            //this.MyModel.Series.Add(new FunctionSeries(Math.Cos, 0, 10, 0.1, "cos(x)"));
            //this.MyModel.Series.Add(new FunctionSeries(Math.Sin, 0, 10, 0.1, "sin(x)"));

            lineSeries = new LineSeries();
            lineSeries.LineStyle = LineStyle.Solid;
            lineSeries.StrokeThickness = 2.0;
            lineSeries.Color = OxyColor.FromRgb(0, 0, 0);

            this.MyModel.Series.Add(lineSeries);

            Timer timer = new Timer(1000);
            timer.Elapsed += Timer_Elapsed;
            timer.Start();

            count = 0;
        }

        private void Timer_Elapsed(object sender, ElapsedEventArgs e)
        {
            lineSeries.Points.Add(new DataPoint(count, Math.Pow(count, 2)));
            this.MyModel.InvalidatePlot(true);

            count++;
        }

        public PlotModel MyModel { get; private set; }
    }
}

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:WpfApp1"
        xmlns:oxy="http://oxyplot.org/wpf" x:Class="WpfApp1.MainWindow"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Window.DataContext>
        <local:MainViewModel/>
    </Window.DataContext>
    <Grid>
        <oxy:PlotView Model="{Binding MyModel}" />
    </Grid>
</Window>