OxyPlot图形不会更新

时间:2018-06-01 18:50:19

标签: c# wpf oxyplot

我正在使用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++;
    }
}

我还需要做其他事吗?

2 个答案:

答案 0 :(得分:1)

使用

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来更新点数。

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

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

是必需的。

答案 1 :(得分:0)

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

视图模型:

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>