LiveCharts повторно отображает весь график при изменении оси (MinValue и MaxValue) или добавлении новых данных

Я создал LineChart с 5 диаграммами. У каждого по 250 баллов: по 1 баллу каждые 1 мин. У меня есть кнопка, которая перемещает MinValueX и MaxValueX. И событие UserControl_MouseDown, которое добавляет новые данные на 1 график. Но когда я вызываю это, ему требуется 15-20 секунд, чтобы переместить или добавить данные в график. Думаю, 1250 баллов - это не много. Похоже, он снова рисует весь график, вместо того, чтобы перемещать его или добавлять новые данные.

Можно как-нибудь изменить поведение рендеринга на более оптимальное?

Вот мой элемент управления LineChart:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using LiveCharts;
using LiveCharts.Defaults;
using LiveCharts.Wpf;

namespace Chart
{
    /// <summary>
    /// Interaction logic for LineChart2.xaml
    /// </summary>
    public partial class LineChart2 : UserControl, INotifyPropertyChanged
    {
        #region properties
        public SeriesCollection SeriesCollection { get; set; }
        private Dictionary<string, List<DateTimePoint>> SeriesFullCollection { get; set; }
        public Func<double, string> XFormatter { get; set; }
        public long AxisStep { get; set; }
        public double MinValueX { get; set; }
        public double MaxValueX { get; set; }

        private DateTime minValueXDate;
        public DateTime MinValueXDate
        {
            get { return minValueXDate; }
            set { minValueXDate = value;
                MinValueX = value.Ticks;
                OnPropertyChanged("MinValueX");
            }
        }
        private DateTime maxValueXDate;
        public DateTime MaxValueXDate
        {
            get { return maxValueXDate; }
            set
            {
                maxValueXDate = value;
                MaxValueX = value.Ticks;
                OnPropertyChanged("MaxValueX");
            }
        }
        public double MinValueY { get; set; }
        public double MaxValueY { get; set; }
        public int ChartButtonsId { get; set; }
        #endregion
        public LineChart2()
        {
            SeriesFullCollection = new Dictionary<string, List<DateTimePoint>>();
            SeriesCollection = new SeriesCollection();
            this.Loaded += ControlLoaded;                     
            DataContext = this;            
            InitializeComponent();       
        }

        private void ControlLoaded(object sender, RoutedEventArgs e)
        {
            MinValueXDate = DateTime.Now.AddHours(-3.5);
            MaxValueXDate = DateTime.Now.AddHours(0.5);
            AxisStep = TimeSpan.FromMinutes(15).Ticks;
            XFormatter = val => new DateTime((long)val).ToString("HH:mm");

            MinValueY = 0;            //Test
            MaxValueY = 20;            //Test
            //Test
            Text2Add("A");
            Text2Add("B");
            Text2Add("C");
            Text2Add("D");
            Text2Add("E");
            RefreshCollection();
        }

        #region Add/Update/Remove
        public void AddChart(string title, Dictionary<DateTime, double> data)
        {
            List<DateTimePoint> dateTimePoints = new List<DateTimePoint>();
            foreach (var item in data)
                dateTimePoints.Add(new DateTimePoint(item.Key, item.Value));

            SeriesFullCollection.Add(title, dateTimePoints);
            AddToCollection(title);
        }
        public void UpdateChart(string title, Dictionary<DateTime, double> data)
        {
            var series = SeriesCollection.FirstOrDefault(x => x.Title == title);
            var seriesfull = SeriesFullCollection.FirstOrDefault(x => x.Key == title);
            if (series != null)
                foreach (var item in data)
                {
                    series.Values.Add(new DateTimePoint(item.Key, item.Value));
                    seriesfull.Value.Add(new DateTimePoint(item.Key, item.Value));
                }
        }
        public void RemoveChart(string title)
        {
            var series = SeriesCollection.FirstOrDefault(x => x.Title == title);
            var seriesfull = SeriesFullCollection.FirstOrDefault(x => x.Key == title);
            if (series != null)
            {
                SeriesCollection.Remove(series);
                SeriesFullCollection.Remove(seriesfull.Key);
            }
            RefreshCollection();
        }

        private void AddToCollection(string title)
        {
            var seriesfull = SeriesFullCollection.FirstOrDefault(x => x.Key == title);
            var l = new LineSeries();
            l.Title = seriesfull.Key;
            l.Values = new ChartValues<DateTimePoint>();
            l.PointGeometrySize = 2;
            l.Values.AddRange(seriesfull.Value.Where(x => x.DateTime >= MinValueXDate && x.DateTime <= MaxValueXDate));
            SeriesCollection.Add(l);
        }
        #endregion
        #region EventsMethod
        public void MoveNext()
        {
            MinValueXDate = MinValueXDate.AddTicks(AxisStep * 2);
            MaxValueXDate = MaxValueXDate.AddTicks(AxisStep * 2);
            //RefreshCollection();
        }
        public void MovePrevious()
        {
            MinValueXDate = MinValueXDate.AddTicks(-AxisStep * 2);
            MaxValueXDate = MaxValueXDate.AddTicks(-AxisStep * 2);
            //RefreshCollection();
        }
        public void ZoomIn()
        {
            MinValueXDate = MinValueXDate.AddTicks(AxisStep);
            MaxValueXDate = MaxValueXDate.AddTicks(-AxisStep);
            //RefreshCollection();
        }
        public void ZoomOut()
        {
            MinValueXDate = MinValueXDate.AddTicks(-AxisStep);
            MaxValueXDate = MaxValueXDate.AddTicks(AxisStep);
            //RefreshCollection();
        }
        public void ChangeDate()
        {

        }
        #endregion
        private void RefreshCollection()
        {
            SeriesCollection.Clear();
            foreach (var item in SeriesFullCollection)
            {
                var l = new LineSeries();
                l.Title = item.Key;
                l.Values = new ChartValues<DateTimePoint>();
                l.PointGeometrySize = 2;
                l.Values.AddRange(item.Value.Where(x => x.DateTime >= MinValueXDate && x.DateTime <= MaxValueXDate));
                SeriesCollection.Add(l);
            }
        }
        #region Test
        private void Text2Add(string name)
        {
            var d = new Dictionary<DateTime, double>();
            int last = 0;
            Random r = new Random();
            for (int i = 0; i < 250; i++)
            {
                var next = r.Next(last == 0 ? 0 : last - 1, last == 20 ? 20 : last + 2);
                last = next;
                d.Add(DateTime.Now.AddMinutes(-250+ i), next);
            }
            AddChart(name, d);
        }
        private int aaaa = 0;

        public event PropertyChangedEventHandler PropertyChanged;

        private void UserControl_MouseDown(object sender, MouseButtonEventArgs e)
        {
            var d = new Dictionary<DateTime, double>();
            int last = 0;
            Random r = new Random();
            for (int i = 0; i < 10; i++)
            {
                var next = r.Next(last == 0 ? 0 : last - 1, last == 20 ? 20 : last + 2);
                last = next;
                d.Add(DateTime.Now.AddMinutes(aaaa + i), next);
            }
            aaaa += 10;
            UpdateChart("A", d);
        }
        #endregion
        protected void OnPropertyChanged(string name)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            MinValueXDate = MinValueXDate.AddTicks(AxisStep * 2);
            MaxValueXDate = MaxValueXDate.AddTicks(AxisStep * 2);
        }
    }
}

И Xaml:

<UserControl x:Class="Chart.LineChart2"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         xmlns:lvc="clr-namespace:LiveCharts.Wpf;assembly=LiveCharts.Wpf"
         xmlns:local="clr-namespace:Chart"
         mc:Ignorable="d" 
         d:DesignHeight="300" d:DesignWidth="800" MouseDown="UserControl_MouseDown">
    <Grid Background="White">
        <lvc:CartesianChart Series="{Binding SeriesCollection}" LegendLocation="Right" >
            <lvc:CartesianChart.AxisY>
                <lvc:Axis Title="Value" MinValue="{Binding MinValueY}" MaxValue="{Binding MaxValueY}"></lvc:Axis>
            </lvc:CartesianChart.AxisY>
            <lvc:CartesianChart.AxisX>
                <lvc:Axis LabelFormatter="{Binding XFormatter}" MinValue="{Binding MinValueX}" MaxValue="{Binding MaxValueX}">
                    <lvc:Axis.Separator>
                        <lvc:Separator Step="{Binding AxisStep}" />
                    </lvc:Axis.Separator>
                </lvc:Axis>
            </lvc:CartesianChart.AxisX>
        </lvc:CartesianChart>
        <Button Height="20" Width="50" Click="Button_Click" Margin="740,10,10,270"/>
    </Grid>
</UserControl>

person Silny ToJa    schedule 12.02.2021    source источник


Ответы (1)


Есть ссылка на страницу с советами по эффективности.

Предлагаемые возможности для повышения производительности:

  • Отключить анимацию ‹lvc: CartesianChart DisableAnimations = True /›
  • Уменьшите количество фигур в диаграмме
  • Заморозь все, что можешь
  • Избегайте вызова .Add () несколько раз

Так что в вашем случае я бы попробовал хотя бы первое и последнее предложение.

person user2250152    schedule 12.02.2021
comment
Установка CartesianChart DisableAnimations = True имеет большое значение. Но что вы имеете в виду, заморозить все, что сможете? Вы думаете о других процессах в приложении? - person Silny ToJa; 12.02.2021
comment
@SilnyToJa В WPF замораживаемые объекты - это кисти, анимация и т. Д. Но из вашего кода вы не используете и не ссылаетесь на какие-либо замораживаемые объекты. Дополнительную информацию можно найти здесь: docs.microsoft.com/en-us/dotnet/desktop/wpf/advanced/ - person user2250152; 12.02.2021