График OxyPlot не обновляется - PullRequest
0 голосов
/ 01 июня 2018

Я разрабатываю приложение WPF на C #, .NET Framework 4.7.и Oxyplot 1.0.

Я пытаюсь обновить графику во время выполнения, но она ничего не делает.

Я пытался использовать ObsevableCollection и InvalidateFlag, но безуспешно.

Это 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 голосов
/ 02 июня 2018

Я создал этот небольшой пример, чтобы показать, как обновлять графику во время выполнения.Надеюсь, это поможет!

ViewModel:

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>
0 голосов
/ 01 июня 2018

С

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

вы заменяете полный ItemsSource сюжета.Так как нет никакого уведомления о просмотре путем вызова RaisePropertyChangedEvent после этого, связанный график не распознает изменение и график не обновит его точки.

Существует два возможных решения:

1.Используйте INotifyPropertychanged , вызывая RaisePropertyChangedEvent после замены коллекции.Поэтому

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.

Обратите внимание, что необходимо использовать поток пользовательского интерфейса для изменения элементов ObservableCollection, как описано в в этом вопросе .Поскольку вы используете другой поток для добавления значений, вызывается пользовательский интерфейс, например

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

.

...