我有一个WinForm从可用数据中绘制图表。
我对它进行了编程,以便每{1}个事件调用一个函数:
现在要绘制的数据真的很大,需要花费大量时间才能更新我的表单。 Winform.Timer.Tick
也依赖于Winform.Timer.Tick
,因此它在表单的同一个线程中执行。
这两件事使我的形式非常反应迟钝。
我该怎么做才能解决这个问题?
我想到了以下内容:
WM_TIMER
的使用并开始使用Winform.Timer
System.Threading.Timer
模式,因此我将依赖.NET IsInvokeRequired
。由于我有大量数据,这是个好主意吗? 我担心在某些时候ThreadPool也会太长或太大。
你能否就我的问题向我提出建议?
非常感谢!
AFG
答案 0 :(得分:2)
将数据提取移动到线程是个好主意。您可以使用BackgroundWorker以无限循环的方式获取数据
Sleep(remainingTime)
以获得所需的频率。答案 1 :(得分:1)
我会在无限循环中使用System.Timers.Timer覆盖BackgroudWorker BackgroundWorker是从ThreadPool执行的,而并不意味着在应用程序的生命周期内运行。
System.Timers.Timer的动机:
这是我的建议:
在方法开始时禁用计时器,然后在结束时再次重新启用计时器,将满足在已用事件中完成的工作量超过计时器间隔的情况。这还可确保更新之间的计时器保持一致。我已经添加了一个额外的预防措施锁。
我使用匿名方法来更新UI线程,但你可以随心所欲地做到这一点,只要你记得Invoke
,检查InvokeRequired
属性也是一个好主意。
private readonly object chartUpdatingLock = new object();
private void UpdateChartTimerElapsed(object sender, ElapsedEventArgs e)
{
// Try and get a lock, this will cater for the case where two or more events fire
// in quick succession.
if (Monitor.TryEnter(chartUpdatingLock)
{
this.updateChartTimer.Enabled = false;
try
{
// Dequeuing and whatever other work here..
// Invoke the UI thread to update the control
this.myChartControl.Invoke(new MethodInvoker(delegate
{
// Do you UI work here
}));
}
finally
{
this.updateChartTimer.Enabled = true;
Monitor.Exit(chartUpdatingLock);
}
}
}
答案 2 :(得分:1)
使用后台计时器你不太可能领先。您的图表控件几乎肯定需要从创建的同一个线程更新。任何具有可见外观的控件都可以。这要求您在Elapsed事件处理程序中使用Control.BeginInvoke,以便更新代码在UI线程上运行。出列数据可能不是很昂贵,实际上你可以通过调用使它变慢。并且还没有从UI线程中消除压力。
你也会有一个潜在的严重限制问题,即使UI线程无法跟上,计时器也会继续滴答作响并提取数据。这最终会使你的程序崩溃。
相反,请考虑使更新图表的代码更智能。如果此类详细信息至少为像素宽,则图表只能显示数据的详细信息。实际上,它只能显示有效信息的2000像素。这并不多,更新2000个数据点不应该造成任何麻烦。