【问题标题】:LiveCharts re-renders the entire plot when changing axis (MinValue and MaxValue) or adding new dataLiveCharts 在更改轴(MinValue 和 MaxValue)或添加新数据时重新渲染整个绘图
【发布时间】:2021-02-12 11:07:42
【问题描述】:

我创建了一个包含 5 个图表的 LineChart。每个有 250 分:每 1 分钟 1 分。我有一个移动 MinValueX 和 MaxValueX 的按钮。以及一个将新数据添加到 1 个图表的事件 UserControl_MouseDown。但是当我调用它时,它需要 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>

【问题讨论】:

    标签: c# wpf charts livecharts


    【解决方案1】:

    有一个指向带有peformance tips的页面的链接。

    获得更好性能的建议可能性是:

    • 禁用动画
    • 减少图表中的形状数量
    • 尽可能冻结
    • 避免多次调用 .Add()

    所以在你的情况下,我至少会尝试第一个和最后一个建议。

    【讨论】:

    • 设置 CartesianChart DisableAnimations = "True" 有很大的不同。但是你的意思是“尽可能冻结”?您考虑过应用中的其他流程吗?
    • @SilnyToJa 在 WPF 中,可冻结对象是画笔、动画等。但是从您的代码中,您不会使用或引用任何可冻结对象。更多信息可以在这里找到:docs.microsoft.com/en-us/dotnet/desktop/wpf/advanced/…
    猜你喜欢
    • 2020-02-07
    • 1970-01-01
    • 2022-11-21
    • 1970-01-01
    • 2018-04-24
    • 1970-01-01
    • 1970-01-01
    • 2020-10-30
    • 2020-12-14
    相关资源
    最近更新 更多