LiveCharts 在更改轴(MinValue 和 MaxValue)或添加新数据时重新呈现整个图
LiveCharts re-renders the entire plot when changing axis (MinValue and MaxValue) or adding new data
我创建了一个包含 5 个图表的折线图。每个有 250 点:每 1 分钟 1 点。我有一个移动 MinValueX 和 MaxValueX 的按钮。以及将新数据添加到 1 个图表的事件 UserControl_MouseDown。但是当我调用它时,它需要 15-20 秒才能将数据移动或添加到绘图中。我认为1250点不是很多。看起来它重新绘制了整个图形,而不是移动它或添加新数据。
我能否以某种方式将渲染行为更改为更优化?
这是我的折线图控件:
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>
有一个 link 要分页 peformance tips。
获得更好性能的建议可能性是:
- 禁用动画
- 减少图表中的形状数量
- 尽可能冻结
- 避免多次调用 .Add()
所以对于你的情况,我至少会尝试第一个和最后一个建议。
我创建了一个包含 5 个图表的折线图。每个有 250 点:每 1 分钟 1 点。我有一个移动 MinValueX 和 MaxValueX 的按钮。以及将新数据添加到 1 个图表的事件 UserControl_MouseDown。但是当我调用它时,它需要 15-20 秒才能将数据移动或添加到绘图中。我认为1250点不是很多。看起来它重新绘制了整个图形,而不是移动它或添加新数据。
我能否以某种方式将渲染行为更改为更优化?
这是我的折线图控件:
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>
有一个 link 要分页 peformance tips。
获得更好性能的建议可能性是:
- 禁用动画
- 减少图表中的形状数量
- 尽可能冻结
- 避免多次调用 .Add()
所以对于你的情况,我至少会尝试第一个和最后一个建议。