▪ 场景:
采用 ChartControl:XYDiagram2D(折线图),从示波器里实时采集 600 个点数据并显示在 折线图 中。
▪ 问题:
假设我们实时采集数据的时间间隔是 0.5 秒,但是由于 ChartControl 控件 重绘这 600 个点所需的时间大于这个时间间隔,并且随着程序的执行内存的消耗,重绘时间将还会大一点,从而导致了 折线图 的数据大大延迟于示波器的实时数据。
同时由于 ChartControl 控件 一直占用主UI线程,导致整个界面响应卡顿。
▪ 解决
使用 .BeginInit()
和 .EndInit()
的方法来避免不必要的更新,从而缩短重绘的时间。
使用时需要注意,如果你已经明确经常更新的是折线图的某个部位(比如某条折线条,某个条线条的点集合等等),那么最好直接使用其对应对象的 .BeginInit()
和 .EndInit()
,这样性能将提高更多。
例如: 实时更新第2条的折线条点集合,最好直接调用其对象的 uiChart.Diagram.Series[1].Points.BeginInit() / .EndInit()
,这样能明确让系统不去更新折线图的其他UI部位,性能更高。
当然你可以使用
uiChart.BeginInit() / .EndInit()
,但是其效果不如上面的代码
▪ 源码
/// <summary>
/// 定时器集合
/// </summary>
private Dictionary<string, Timer> appTimers = null;
private Dictionary<string, bool> appTimerLocks = null;
/// <summary>
/// 构造函数
/// </summary>
public MainWindow()
{
InitializeComponent();
// 初始化
this.appTimers = new Dictionary<string, Timer>();
this.appTimerLocks = new Dictionary<string, bool>();
// 图表初始化
uiChart_Init();
// 图表定时器启用
this.appTimers.Add("uiChart_Timer", new Timer(this.uiChart_Timer,null,0,500));
this.appTimerLocks.Add("uiChart_Timer", false);
}
/// <summary>
/// 图表初始化
/// </summary>
private void uiChart_Init()
{
// 此处是初始化图表的一些显示参数
// 代码忽略,详见《DevExpress 控件快速上手之 ChartControl:XYDiagram2D(折线图)》
}
/// <summary>
/// 图表的定时器回调函数
/// </summary>
/// <param name="o"></param>
private void uiChart_Timer( object o )
{
// 如果定时器正处于锁定状态,那么结束回调函数
// 这样做主要作用就是确保无论定时器触发时间有多短,都可以保证同一时刻只能执行一个回调函数
if( this.appTimerLocks.ContainsKey("uiChart_Timer") && this.appTimerLocks["uiChart_Timer"] == true ) return;
// 定时器加锁
this.appTimerLocks["uiChart_Timer"] = true;
// 初始化
Random random = new Random();
SeriesPointCollection seriesPointCollection = new SeriesPointCollection();
for( int i = 0; i <= 600; i++ ) seriesPointCollection.Add(new SeriesPoint(i,random.Next(-10,10))); // 生成 100个(X轴) 0~10 随机值(Y轴)的点
// UI 应用
this.Dispatcher.Invoke(new Action(()=> {
uiChart.Diagram.Series[0].Points.BeginInit(); // 【优化的代码】效果更好
uiChart.Diagram.Series[0].Points.Clear();
uiChart.Diagram.Series[0].Points.AddRange(seriesPointCollection);
uiChart.Diagram.Series[0].Points.BeginInit(); // 【优化的代码】效果更好
}));
// 定时器解锁
this.appTimerLocks["uiChart_Timer"] = false;
}
▪ 总结
效果提升明显。