简体   繁体   中英

OxyPlot not refreshing when using data binding in WPF

I'm asynchonrously getting data and attempting to populate a plot via the LineSeries, except the plot does not refresh when the bound collection (ObservableCollection) is updated. Note: I have a XAML behavior to call InvalidatePlot(true) when the bound collection changes.

Can anyone explain why the plot is not updating as expected?

WPF .Net 4.0 OxyPlot 2014.1.293.1

I have the following XAML datatemplate, as you can see the LineSeries ItemsSource is bound to a property (PlotData) in the ViewModel:

<DataTemplate DataType="{x:Type md:DataViewModel}">

    <Grid>

        <oxy:Plot x:Name="MarketDatePlot"
                    Margin="10">
            <oxy:Plot.Axes>
                <oxy:DateTimeAxis Position="Bottom"
                                    StringFormat="dd/MM/yy"
                                    MajorGridlineStyle="Solid"
                                    MinorGridlineStyle="Dot"
                                    IntervalType="Days"
                                    IntervalLength="80" />
                <oxy:LinearAxis Position="Left"
                                MajorGridlineStyle="Solid"
                                MinorGridlineStyle="Dot"
                                IntervalLength="100" />
            </oxy:Plot.Axes>
            <oxy:LineSeries ItemsSource="{Binding Path=PlotData, Mode=OneWay}" />
            <i:Interaction.Behaviors>
                <behaviors:OxyPlotBehavior ItemsSource="{Binding Path=PlotData, Mode=OneWay}" />
            </i:Interaction.Behaviors>
        </oxy:Plot>
    </Grid>

</DataTemplate>

As I said the ViewModel requests and populates the bound collection asynchronously (the actual population of bound collection happens on the UI thread):

public sealed class DataViewModel : BaseViewModel, IDataViewModel
{
    private readonly CompositeDisposable _disposable;
    private readonly CancellationTokenSource _cancellationTokenSource;
    private readonly RangeObservableCollection<DataPoint> _plotData;

    public DataViewModel(DateTime fromDate, DateTime toDate, IMarketDataService marketDataService, ISchedulerService schedulerService)
    {
        _plotData = new RangeObservableCollection<DataPoint>();
        _disposable = new CompositeDisposable();

        if (fromDate == toDate)
        {
            // nothing to do...
            return;
        }

        _cancellationTokenSource = new CancellationTokenSource();

        _disposable.Add(Disposable.Create(() =>
        {
            if (!_cancellationTokenSource.IsCancellationRequested)
            {
                _cancellationTokenSource.Cancel();
            }
        }));

        marketDataService.GetDataAsync(fromDate, toDate)
            .ContinueWith(t =>
            {
                if (t.IsFaulted)
                {
                    throw new Exception("Failed to get market data!", TaskHelper.GetFirstException(t));
                }

                return t.Result.Select(x => new DataPoint(DateTimeAxis.ToDouble(x.Time), x.Value));
            }, schedulerService.Task.Default)
            .SafeContinueWith(t => _plotData.AddRange(t.Result), schedulerService.Task.CurrentSynchronizationContext);
    }

    public void Dispose()
    {
        _disposable.Dispose();
    }

    public IEnumerable<DataPoint> PlotData
    {
        get { return _plotData; }
    }
}

And the XAML behavior looks like this:

(I can't seem to paste in anymore code, SO keeps throwing an error on save)

OxyPlot does not automatically update when you add data.

You must call plotname.InvalidatePlot(true);

and it must run on the UI dispatcher thread, ie

Dispatcher.InvokeAsync(() => 
{
    plotname.InvalidatePlot(true);
}

Don't know if people still need this but I was having the same problems with itemsource not updating chart. And none of the existing solutions helped me.

Well I've finally found the reason why whole thing didn't work. I've assigned my collection to itemsource before I actually initialized it (new Observable....).

When i tried assigning already initialized collection to my itemsource, whole thing started working.

Hope this helps someone.

I know this is an old question but maybe someone will use my answer after hours of double checking. I use MVVM. I'm updating the data with await Task.Run(()=> update()); and that wasn't rendering my plot in my UI. I was also initializing my PlotModel before setting it. Turns out, initializing the PlotModel in that update() method wasn't registering in my UI. I had to initialize it before I called that Task to run.

public ViewModel()
{
     Plot = new PlotModel(); //(Plot is a property using 
                             // INotifyPropertyChanged)
     PlotGraph = new RelayCommand(OnPlotGraph);
}

public RelayCommand PlotGraph {get; set;}

private async void OnPlotGraph()
{
     await Task.Run(() => Update());
}

private void Update()
{
    var tempPlot = new PlotModel();
    //(set up tempPlot, add data to tempPlot)
    Plot = tempPlot;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM