C# 使用WPF和Oxyplot缓慢更新UI
我想在这里完成的是,我想从一个CSV文件中获取一些数据,然后从一个文件夹复制到一个临时文件夹中(这样我就不会篡改原始文件) 然后,我想读取CSV文件中的所有数据,并使用Oxyplot中的散点序列在图形上绘制最后2000个数据点(我想每200ms检查一次新数据,所以我使用了调度程序计时器)。我遇到的问题是,最初几次更新的情节看起来很棒,它的情节正是我想要的。。。但是,在12次更新之后,图形不会更新,或者更新速度非常慢,导致UI变得无响应 下面是我的代码为这一部分的项目C# 使用WPF和Oxyplot缓慢更新UI,c#,wpf,csv,oxyplot,C#,Wpf,Csv,Oxyplot,我想在这里完成的是,我想从一个CSV文件中获取一些数据,然后从一个文件夹复制到一个临时文件夹中(这样我就不会篡改原始文件) 然后,我想读取CSV文件中的所有数据,并使用Oxyplot中的散点序列在图形上绘制最后2000个数据点(我想每200ms检查一次新数据,所以我使用了调度程序计时器)。我遇到的问题是,最初几次更新的情节看起来很棒,它的情节正是我想要的。。。但是,在12次更新之后,图形不会更新,或者更新速度非常慢,导致UI变得无响应 下面是我的代码为这一部分的项目 public Mai
public MainWindow()
{
viewModel = new View_Model.MainWindowModel();
DataContext = viewModel;
CompositionTarget.Rendering += CompositionTargetRendering;
InitializeComponent();
}
private void AutoUpdateGraph() //begins when a check box IsChecked = true
{
sw.Start();
System.Windows.Threading.DispatcherTimer dispatcherTimer = new System.Windows.Threading.DispatcherTimer();
dispatcherTimer.Tick += new EventHandler(dispatcherTimer_Tick);
dispatcherTimer.Interval = new TimeSpan(0, 0, 0, 0, 200);
dispatcherTimer.Start();
}
private void dispatcherTimer_Tick(object sender, EventArgs e)
{
SleeveData sd = new SleeveData(); //class to deal with the data
FileManagement fm = new FileManagement(); //class to manage the files
string date = fm.GetDate(); //get the current date to use in finding the
//most recent CSV file
_newPath = fm.InitialFileSetup(date); //create a new path for the temp file
fm.RewriteFile(_newPath); //write the temp file to the temp path
if (fm.IsFileLocked(_newPath) == false) //checking if the file is being written to
{
IEnumerable<SleeveData> newSD = sd.GetMostRecentCSVData(_newPath); //getting the latest data from the temp file
viewModel.LoadData(newSD); //updating the data on the graph
}
}
public主窗口()
{
viewModel=新视图_Model.MainWindowModel();
DataContext=viewModel;
CompositionTarget.Rendering+=CompositionTargetRendering;
初始化组件();
}
private void AutoUpdateGraph()//在选中复选框时开始=true
{
sw.Start();
System.Windows.Threading.dispatchermer dispatchermer=新的System.Windows.Threading.dispatchermer();
dispatchermer.Tick+=新事件处理程序(dispatchermer\u Tick);
Dispatchermer.Interval=新的时间跨度(0,0,0,0,200);
dispatchermer.Start();
}
私有void Dispatcher_Tick(对象发送方,事件参数e)
{
SleeveData sd=new SleeveData();//处理数据的类
FileManagement fm=new FileManagement();//类来管理文件
string date=fm.GetDate();//获取用于查找
//最新的CSV文件
_newPath=fm.InitialFileSetup(date);//为临时文件创建一个新路径
RewriteFile(_newPath);//将临时文件写入临时路径
if(fm.IsFileLocked(_newPath)==false)//检查文件是否正在写入
{
IEnumerable newSD=sd.GetMostRecentCSVData(_newPath);//从临时文件获取最新数据
viewModel.LoadData(newSD);//更新图形上的数据
}
}
这是MainWindowModel中的LoadData方法
public void LoadData(IEnumerable<SleeveData> newData)
{
var scatterSeries1 = new OxyPlot.Series.ScatterSeries
{
MarkerSize = 3,
Title = string.Format("Sleeve Data"),
};
int j = 0;
var zeroBuffer = new List<float>(new float[2000]);
var fDiaDataBuffer = zeroBuffer.Concat((newData.Select(x => x.fDiameter).ToList())).ToList();
var iDiaDataBuffer = zeroBuffer.Concat((newData.Select(x => x.IDiaMax).ToList())).ToList();
for (int i = fDiaDataBuffer.Count - 2000; i <= fDiaDataBuffer.Count - 1; i++)
{
scatterSeries1.Points.Add(new ScatterPoint(j, fDiaDataBuffer[i]));
j++;
}
PlotModel.Series.Clear();
PlotModel.Series.Add(scatterSeries1);
}
public void LoadData(IEnumerable newData)
{
var scatterSeries1=新OxyPlot.Series.ScatterSeries
{
MarkerSize=3,
Title=string.Format(“套管数据”),
};
int j=0;
var zeroBuffer=新列表(新浮点[2000]);
var fDiaDataBuffer=zeroBuffer.Concat((newData.Select(x=>x.fDiameter.ToList()).ToList();
var iDiaDataBuffer=zeroBuffer.Concat((newData.Select(x=>x.IDiaMax.ToList()).ToList();
对于(inti=fDiaDataBuffer.Count-2000;i一些建议:
在LoadData()方法中使用秒表来查看它需要多长时间。您不会说这些文件中有多少数据,但Linq的一些东西似乎可以从一些优化中受益-在同一组数据上有许多ToLists()
和重复的选择
。类似如下:
var sw = new Stopwatch();
sw.Start();
... do your stuff
Debug.WriteLine(sw.ElapsedMilliseconds);
您也可以尝试在计时器委托中使用秒表,以查看整个“周期”需要多长时间,以防它需要超过200毫秒。我不知道调度程序是否会出现重入,即在前一个“滴答”完成之前计时器再次启动,这会降低性能
问题可能出在您的图表组件上。我在使用大型WPF数据网格时遇到过类似的问题-创建数据并不特别费力-需要花费时间的是渲染。在LoadData()的末尾我看到您清除了图表系列,然后重新填充它。我发现对大型DataGrid的数据源执行此操作会产生“双重打击”,因为它会在清除()之后呈现,然后在重新填充数据后再次渲染。我不熟悉OxyPlot,但如果可行,请查看是否可以找到替代方法,例如重新使用序列,而不是清除并再次添加
如果OxyPlot的性能确实很差,那么购买不同的图表组件是一种选择吗?我可以完全推荐SciChart,我们已经将其用于各种高性能/高容量的科学图表应用程序(顺便说一句,我与他们没有关系!).谢谢你的回复!我确实用秒表来监控抓取数据所花的时间,它会越来越大,因为CSV文件一直在被写入(最长的时间几乎是300毫秒,我只希望我的应用程序每隔200毫秒检查一次新数据)。我不确定数据的大小是否导致了问题,因为我只获取了最后2000个点并绘制它们。我认为您对渲染中存在的瓶颈是正确的,尽管我对C#缺乏经验,但我发现很难找出如何添加到序列中。还有,那些ToList()s是时髦的…*发现很难添加到序列中,而不是将其删除并完全重建。我希望图形是一种运行样式,表示右侧的最新数据。当收到新数据时,数据会被推到左侧…这是我可以完成此任务的唯一方法。@JoshRyan假设不断添加行对于从未删除的文件,如何跟踪您绘制的最后一个行号。在下一个计时器勾选时,读取文件并跳过此行号,然后遍历所有剩余的行,创建散点并将其添加到现有系列(类似于PlotModel.series[0].Points.add(…)'))。如果系列中的点数为2001,则
PlotModel.series.RemoveAt(0)`,这将为您提供“运行”的打印样式。无需在每个刻度上清除并重新创建整个系列!@JoshRyan我认为对于文件大小不断增长的问题,您无能为力。您已经