上一篇文章中讲了WPF中自定义绘制大量数据的图标,思路是先将其绘制在内存,然后一次性加载到界面,在后续的调试过程中,发现当数据量到达10W时,移动鼠标显示数据有明显的延迟。经过思考,我采用了以下两个办法解决这个问题:
1.将数据显示的文本与图表分离,作为一个单独的canvas,这样,显示文本数据的时候就不需要重画图表了
2.计算鼠标移动速度,当移动速度过快时,不绘制文本,减少数据文本的绘制频率
3.使用START_INDEX 和 END_INDEX来表示绘制数据的其实位置和结束位置,减少对整个数据的遍历
首先看前台代码
<UserControl x:Class="Zero_Gjy.UserControls.DrawChart"
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:local="clr-namespace:Zero_Gjy.UserControls"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<ScrollViewer >
<Grid x:Name="linechart" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
</Grid>
</ScrollViewer>
</UserControl>
在lineChart中分别加入图表的Canvas和文本数据的Canvas,修改之前的DrawingCanvas,把绘制数据文本的代码分离出来
DrawingCanvas.CS
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Threading;
namespace Zero_Gjy.UserControls
{
public class DrawingCanvas : Canvas
{
private List<Visual> visuals = new List<Visual>();
public const double YZero = 50;
public const double YMargin = 50;
private double YLabelLen = 5;
private double yHeight;
private Brush line1Color = Brushes.Black;
private Brush labelColor = Brushes.Black;
private Brush axisColor = Brushes.Black;
private Brush line2Color = Brushes.Black;
private double thinkness = 1;
private double canvasWidth = 0;
private double xWidth;
private const int yLinesCount = 12;
List<LineDatas> allDatas;
private double canvasHeight;
int dataCount = 0;
int rtCount = 0;
public enum MouseMode
{
ZOOM,
VIEW
}
public MouseMode mMode = MouseMode.VIEW;
public DrawingCanvas()
{
this.Background = Brushes.Transparent;
this.HorizontalAlignment = HorizontalAlignment.Left;
this.VerticalAlignment = VerticalAlignment.Top;
this.Margin = new Thickness(0, 0, 0, YMargin);
AllDatas = new List<LineDatas>();
}
//获取Visual的个数
protected override int VisualChildrenCount
{
get { return visuals.Count; }
}
//获取Visual
protected override Visual GetVisualChild(int index)
{
return visuals[index];
}
//添加Visual
public void AddVisual(Visual visual)
{
visuals.Add(visual);
base.AddVisualChild(visual);
base.AddLogicalChild(visual);
}
//删除Visual
public void RemoveVisual(Visual visual)
{
visuals.Remove(visual);
base.RemoveVisualChild(visual);
base.RemoveLogicalChild(visual);
}
//命中测试
public DrawingVisual GetVisual(Point point)
{
HitTestResult hitResult = VisualTreeHelper.HitTest(this, point);
return hitResult.VisualHit as DrawingVisual;
}
//使用DrawVisual画Polyline
//DrawingVisual lineVisual;
public void addData(string title,double min,double max,DoubleCollection xData, DoubleCollection mData, DoubleCollection sData)
{
AllDatas.Add(new LineDatas(title, min, max, xData,mData, sData));
dataCount++;
rtCount = mData.Count;
}
public void removeFirst() {
for(int i = 0; i < AllDatas.Count; i++)
{
AllDatas[i].RtData.RemoveAt(0);
AllDatas[i].ThData.RemoveAt(0);
}
}
public void removeLast()
{
for (int i = 0; i < AllDatas.Count; i++)
{
AllDatas[i].RtData.RemoveAt(AllDatas[i].RtData.Count - 1);
AllDatas[i].ThData.RemoveAt(AllDatas[i].ThData.Count - 1);
}
}
/// <summary>
/// 添加数据点
/// </summary>
/// <param name="xdatas">x坐标</param>
/// <param name="rtdatas">实测数据</param>
/// <param name="thdatas">理论数据</param>
public void addPoint(double[] xdatas,double[] rtdatas,double[] thdatas)
{
if (rtdatas.Length != allDatas.Count)
throw new Exception() { Source="数据个数不匹配"};
for (int i = 0; i < allDatas.Count; i++)
{
AllDatas[i].XData.Insert(0, xdatas[i]);
AllDatas[i].RtData.Insert(0,rtdatas[i]);
AllDatas[i].ThData.Insert(0,thdatas[i]);
if (allDatas[i].Min > rtdatas[i])
allDatas[i].Min = rtdatas[i];
if (allDatas[i].Max < rtdatas[i])
allDatas[i].Max = rtdatas[i];
}
}
//清空所有数据
public void clearData()
{
AllDatas.Clear();
}
//将