Динамические диаграммы с привязкой генерируют необработанное исключение ArgumentOutOfRangeException при увеличении до определенной позиции - PullRequest
2 голосов
/ 25 марта 2019

Я изменил прокручиваемый пример , чтобы использовать VMache Рэйчел Лим с навигационным примером и получить данные из нашей базы данных.Я также перенес некоторую логику с выделенным кодом в ВМ.Все отлично работает с LiveCharts.ChartValues, но при использовании LiveCharts.Geared.GearedValues ​​библиотека вылетает при увеличении / уменьшении масштаба до определенной точки.

Данные имеют 6 часовых значений с отметкой времени.Я группирую и суммирую значения по часам.Временная метка и значения никогда не равны нулю и не являются расчетными суммамиЯ не обновляю данные после того, как диаграмма нарисована.

Если я получу 1000 значений (~ 1000/6 точек данных) из базы данных, библиотека вылетает при уменьшении приблизительно в 5 раз от диапазона данных.Если я получу 10000 значений (~ 10000/6 точек данных), сбой произойдет, как только пользователь перейдет к управлению пользователем, где находится диаграмма.Если я получаю 100000 значений, происходит сбой при приближении приблизительно к тому же минимальному значению и максимальному значению.

Однако при использовании ChartValues ​​вместо GearedValues ​​или при использовании только нескольких точек данных я могу увеличивать масштаб настолько близко, насколько я хочу, и уменьшать масштаб доDateTime.minvalue.

My view.xaml (в основном пример, но с использованием ICommand RangeChangedCommand):

<UserControl 
 [ ....]
  xmlns:geared="clr-namespace:LiveCharts.Geared;assembly=LiveCharts.Geared">

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"></RowDefinition>
        <RowDefinition Height="*"></RowDefinition>
        <RowDefinition Height="100"></RowDefinition>
    </Grid.RowDefinitions>
    <TextBlock Grid.Row="0"></TextBlock>
    <lvc:CartesianChart Grid.Row="1"
                        Zoom="X" 
                        DisableAnimations="True"
                        Hoverable="False">
        <lvc:CartesianChart.Resources>
            <Style TargetType="lvc:Separator">
                <Setter Property="StrokeThickness" Value="2.5"></Setter>
                <Setter Property="Stroke" Value="#E7E7E7"></Setter>
                <Style.Triggers>
                    <Trigger Property="AxisOrientation" Value="X">
                        <Setter Property="IsEnabled" Value="False"></Setter>
                    </Trigger>
                </Style.Triggers>
            </Style>
        </lvc:CartesianChart.Resources>
        <lvc:CartesianChart.Series>
            <geared:GLineSeries StrokeThickness="0" 
                                Values="{Binding Values}"
                                Fill="#2194F1"
                                AreaLimit="0"
                                PointGeometry="{x:Null}"
                                LineSmoothness="0"/>
        </lvc:CartesianChart.Series>
        <lvc:CartesianChart.AxisX>
            <lvc:Axis LabelFormatter="{Binding Formatter}" RangeChangedCommand="{Binding Axis_OnRangeChangedCommand}" 
                      MinValue="{Binding From, Mode=TwoWay}" MaxValue="{Binding To, Mode=TwoWay}"
                      Separator="{x:Static lvc:DefaultAxes.CleanSeparator}"/>
        </lvc:CartesianChart.AxisX>
    </lvc:CartesianChart>
    <lvc:CartesianChart Grid.Row="2" DisableAnimations="True" 
                        ScrollMode="X" 
                        ScrollHorizontalFrom="{Binding From, Mode=TwoWay}"
                        ScrollHorizontalTo="{Binding To, Mode=TwoWay}"
                        ScrollBarFill="#25303030"
                        DataTooltip="{x:Null}"
                        Hoverable="False"
                        Margin="20 10">
        <lvc:CartesianChart.Resources>
            <Style TargetType="lvc:Separator">
                <Setter Property="IsEnabled" Value="False"></Setter>
            </Style>
        </lvc:CartesianChart.Resources>
        <lvc:CartesianChart.Series>
            <geared:GLineSeries Values="{Binding Values}"
                                Fill="Silver"
                                StrokeThickness="0"
                                PointGeometry="{x:Null}"
                                AreaLimit="0"/>
        </lvc:CartesianChart.Series>
        <lvc:CartesianChart.AxisX>
            <lvc:Axis IsMerged="True" 
                      LabelFormatter="{Binding Formatter, Mode=OneTime}" 
                      Foreground="#98000000"
                      FontSize="22"
                      FontWeight="UltraBold"/>
        </lvc:CartesianChart.AxisX>
        <lvc:CartesianChart.AxisY>
            <lvc:Axis ShowLabels="False" />
        </lvc:CartesianChart.AxisY>
    </lvc:CartesianChart>
</Grid>

My VM.cs

class ScrollableVM : ObservableObject, IPageViewModel
{
    public string Name => "Scrollable";
    private double _from;
    private double _to;
    private Func<double, string> _formatter;
    private ICommand _axis_OnRangeChanged;
    public GearedValues<DateTimePoint> Values { get; set; }
    //public ChartValues<DateTimePoint> Values { get; set; }

    #region setget
    public double From
    {
        get { return _from; }
        set
        {
            SetProperty(ref _from, value);
        }
    }
    public double To
    {
        get { return _to; }
        set
        {
            SetProperty(ref _to, value);
        }
    }


    public Func<double, string> Formatter
    {
        get { return _formatter; }
        set
        {
            SetProperty(ref _formatter, value);
        }
    }
    #endregion

    public ScrollableVM()
    {
        var l = new List<DateTimePoint>();


        using (/***getting data from db***/)
        {
            var q =(/***getting data from db***/).Take(1000).ToList();

            var grouped = q.GroupBy(t => new DateTime(t.Stamp.Value.Year, t.Stamp.Value.Month, t.Stamp.Value.Day, t.Stamp.Value.Hour, 0, 0));

            foreach (var item in grouped)
            {
                l.Add(new DateTimePoint((DateTime)item.Key, (double)item.Sum(x => x.value)));
            }
        }
        //Crashes
        //quality doesn't affect crashing
        Values = l.AsGearedValues().WithQuality(Quality.High);

        ////Works
        //Values = new GearedValues<DateTimePoint>() { new DateTimePoint(DateTime.Now, 0), new DateTimePoint(DateTime.Now.AddHours(1), 1) , new DateTimePoint(DateTime.Now.AddHours(2), 2) };


        ////Works
        //Values = l.AsChartValues();

        From = Values.Min(x => x.DateTime).Ticks;
        To = Values.Max(x => x.DateTime).Ticks;
        Formatter = x => new DateTime((long)x).ToString("yyyy");
    }



    private void Axis_OnRangeChanged(RangeChangedEventArgs eventargs)
    {
        var currentRange = eventargs.Range;

        if (currentRange < TimeSpan.TicksPerDay * 2)
        {
            Formatter = x => new DateTime((long)x).ToString("t");
            return;
        }

        if (currentRange < TimeSpan.TicksPerDay * 60)
        {
            Formatter = x => new DateTime((long)x).ToString("dd MMM yy");
            return;
        }

        if (currentRange < TimeSpan.TicksPerDay * 540)
        {
            Formatter = x => new DateTime((long)x).ToString("MMM yy");
            return;
        }

        Formatter = x => new DateTime((long)x).ToString("yyyy");
    }

    public ICommand Axis_OnRangeChangedCommand
    {
        get
        {
            if (_axis_OnRangeChanged == null)
            {
                _axis_OnRangeChanged = new RelayCommand(a => Axis_OnRangeChanged((RangeChangedEventArgs)a));
            }

            return _axis_OnRangeChanged;
        }
    }


}

view.xaml.cs имеет только конструктор с InitializeComponent ()

Сведения об исключении:

 System.ArgumentOutOfRangeException
  HResult=0x80131502
  Message=Specified argument was out of the range of valid values.
Parameter name: index
  Source=WindowsBase
  StackTrace:
   at MS.Utility.FrugalStructList`1.Insert(Int32 index, T value)
   at System.Windows.Media.PathSegmentCollection.Insert(Int32 index, PathSegment value)
   at LiveCharts.Wpf.Points.HorizontalBezierPointView.DrawOrMove(ChartPoint previousDrawn, ChartPoint current, Int32 index, ChartCore chart)
   at LiveCharts.SeriesAlgorithms.LineAlgorithm.Update()
   at LiveCharts.ChartUpdater.Update(Boolean restartsAnimations, Boolean force)
   at LiveCharts.Wpf.Components.ChartUpdater.UpdaterTick(Boolean restartView, Boolean force)
   at LiveCharts.Wpf.Components.ChartUpdater.OnTimerOnTick(Object sender, EventArgs args)
   at System.Windows.Threading.DispatcherTimer.FireTick(Object unused)
   at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
   at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Int32 numArgs, Delegate catchHandler)
   at System.Windows.Threading.DispatcherOperation.InvokeImpl()
   at System.Windows.Threading.DispatcherOperation.InvokeInSecurityContext(Object state)
   at MS.Internal.CulturePreservingExecutionContext.CallbackWrapper(Object obj)
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
   at MS.Internal.CulturePreservingExecutionContext.Run(CulturePreservingExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Windows.Threading.DispatcherOperation.Invoke()
   at System.Windows.Threading.Dispatcher.ProcessQueue()
   at System.Windows.Threading.Dispatcher.WndProcHook(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
   at MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
   at MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o)
   at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
   at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Int32 numArgs, Delegate catchHandler)
   at System.Windows.Threading.Dispatcher.LegacyInvokeImpl(DispatcherPriority priority, TimeSpan timeout, Delegate method, Object args, Int32 numArgs)
   at MS.Win32.HwndSubclass.SubclassWndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam)
   at MS.Win32.UnsafeNativeMethods.DispatchMessage(MSG& msg)
   at System.Windows.Threading.Dispatcher.PushFrameImpl(DispatcherFrame frame)
   at System.Windows.Threading.Dispatcher.PushFrame(DispatcherFrame frame)
   at System.Windows.Application.RunDispatcher(Object ignore)
   at System.Windows.Application.RunInternal(Window window)
   at System.Windows.Application.Run(Window window)
   at System.Windows.Application.Run()
   at medidata.App.Main() in ....\source\repos\medidata\medidata\obj\Debug\App.g.cs:line 51

Версии:

  • LiveCharts 0.9.7.0
  • LiveCharts.Geared 1.2.8.2
  • LiveCharts.Wpf 0.9.7

Есть ли в моем коде / логике что-то напуганное, или я должен сообщить об этой ошибке??Я не нашел подобных проблем, о которых кто-либо еще сообщал.Заранее спасибо.

1 Ответ

0 голосов
/ 26 марта 2019

Ну, это заняло рабочий день, но, думаю, я узнал, что такого отличного в моей реализации от официального примера ... ПОРЯДОК СПИСКА.

Если я сортирую исходные данные по свойству по оси X перед вызовом AsGearedValues ​​(), я не получаю сбоев. Это не проблема в бесплатных версиях AsChartValues. Я предполагаю, что это как-то связано с виртуализацией / оптимизацией, и AsGearedValues ​​не достаточно умен, чтобы сортировать сам список для будущего использования. Также нигде в документации это не упоминается. Я открою вопрос на github по этому поводу.

Простая демонстрация:

MainWindow.xaml.cs

using LiveCharts.Defaults;
using LiveCharts.Geared;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;

namespace bughunt
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public IGearedValues Values { get; set; }

        public MainWindow()
        {
            const int count = 1000;

            //Not sorting causes crashes when zooming deep in and back
            const bool SortBeforePassing = false;

            var r = new Random();

            var datepointlist = new List<DateTimePoint>();

            for (int i = 0; i < count; i++)
            {
                datepointlist.Add(new DateTimePoint(DateTime.Now.AddHours(-i), (double)r.Next(1, 150)));
            }
            if (SortBeforePassing)
            {
                Values = datepointlist.OrderBy(x => x.DateTime).AsGearedValues().WithQuality(Quality.High);
            }
            else
            {
                Values = datepointlist.AsGearedValues().WithQuality(Quality.High);
            }

            DataContext = this;
            InitializeComponent();
        }
    }
}

MainWindow.xaml

<Window x:Class="bughunt.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:bughunt"
        xmlns:lvc="clr-namespace:LiveCharts.Wpf;assembly=LiveCharts.Wpf"
        xmlns:geared="clr-namespace:LiveCharts.Geared;assembly=LiveCharts.Geared"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <lvc:CartesianChart Zoom="X" 
                            DisableAnimations="True"
                            Hoverable="False">

            <lvc:CartesianChart.Series>
                <geared:GLineSeries
                                    Values="{Binding Values}"
                                    PointGeometry="{x:Null}"/>
            </lvc:CartesianChart.Series>
        </lvc:CartesianChart>
    </Grid>
</Window>
...