WPF本机图表控件和持续更新 [英] WPF Native Chart Control and continuous updating

查看:148
本文介绍了WPF本机图表控件和持续更新的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

问题
我正在创建一个C#WPF应用程序,以创建一个简单的折线图,在数据从流读取器到达时绘制点.它将大约每秒更新一次.在处理完所有数据之前,我无法显示图形.在XAML中,我创建了一个窗口,一个网格,然后创建了一个画布.
我的代码使用Observable集合来收集数据点.每次添加一个点都会触发集合更改事件,并从集合中创建一条折线.我清除canvas儿童属性并添加折线.
void Obdatapoints_CollectionChanged(对象发送者,System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
GraphCanvas.Children.Clear();
pl = CreateNewPolyLine(Obdatapoints);
GraphCanvas.Children.Add(pl);

}

我以为添加孩子会导致屏幕重绘.它不是.仅在收到所有点后才绘制.
如何在每个更改的收藏集上重新绘制屏幕?

已经向我建议我使用本机WPF图表控件来执行此任务.我还没有找到任何文档,该文档显示了如何将控件用于不断更新的图表.我每秒大约有1260次更新. WPF图表控件是否支持连续更新并在每次更新后显示图表.

The Problem
I am creating a C# WPF application to create a simple line chart that plots points as the data arrives from a stream reader. It will update about once a second. I cannot get the graph to display until all of the data has been processed. In XAML I create a window, grid and then a canvas.
My code uses an Observable collection to collect the data points. Each time I add a point the collection changed event is fired and I create a polyline from the collection. I clear the canvas children property and add the polyline.
void Obdatapoints_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
GraphCanvas.Children.Clear();
pl = CreateNewPolyLine(Obdatapoints);
GraphCanvas.Children.Add(pl);

}

I thought adding the children would cause the screen to redraw. It does not. It does draw only after all of the points are received.
How can I get the screen to redraw on each collection changed?

It has been suggested to me that I use the native WPF chart control to do this task. I have not found any documentation that shows how to use the control for a chart that is continuously updated. I will have about 1260 updates once each second or so. Will the WPF chart control support continuous updating and display the chart after each update.

推荐答案

对-我看过您的代码.您在这里面临的问题是,您正在UI线程上做所有的事情-您不应该这样做.我要做的是创建一个BackgroundWorker,在其中读取数据并更新ObservableCollection.然后,我在集合更改事件中将数据编组回UI线程.

正如我提到的,您的代码已更改:
Right - I''ve had a look at your code. The issue you''re facing here is that you are doing everything on the UI thread - and you shouldn''t do that. What I did was create a BackgroundWorker in which I read the data in and updated the ObservableCollection. I then marshalled the data back onto the UI thread in the collection changed event.

Here''s your code changed as I mentioned:
using System;
using System.Windows;
using System.Windows.Media;
using System.Windows.Shapes;
using System.IO;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows.Threading;
using System.Collections.Specialized;
///// this is the real realtime graph 
namespace RealTimeGraph
{
 /// <summary>
 /// Interaction logic for MainWindow.xaml
 /// </summary>
 public partial class MainWindow : Window
 {
  public string FullNamePath = @"C:\KarlSample\RealTimeGraph\michael-forks20101201-200256";
  //public string FullNamePath = @"C:\SessionDataTest\michael-forks20101201-200256A";
  private double xmin = 0;
  private double xmax = 1600;
  private double ymin = 850;
  private double ymax = 950;
  private BackgroundWorker _bw = new BackgroundWorker();
  Polyline pl;
  ObservableCollection<Point> Obdatapoints = new ObservableCollection<Point>();
  public MainWindow()
  {
   InitializeComponent();
   _bw = new BackgroundWorker();
   _bw.DoWork += new DoWorkEventHandler(_bw_DoWork);
  }

  void _bw_DoWork(object sender, DoWorkEventArgs e)
  {
   int count = 0;
   string wrkString = null;
   double[] values = new double[4];
   StreamReader sr = new StreamReader(FullNamePath);
   while ((wrkString = sr.ReadLine()) != null)
   {
    System.Threading.Thread.Sleep(500);

    if (wrkString.StartsWith("\""))
    {
     wrkString = sr.ReadLine();
    }
    else
    {
     values = ParseTextStream(wrkString);
     Point pt = new Point(count, values[0]);
     Obdatapoints.Add(pt);
     count++;
    }
   }
  }

  void Obdatapoints_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
  {
   //GraphCanvas.Children.Clear();
   this.Dispatcher.Invoke( DispatcherPriority.DataBind, new Action(()=>{
    pl = CreateNewPolyLine(Obdatapoints);//(NormalizePoint(pt)) in the CreatePolyLineMethod
    GraphCanvas.Children.Add(pl);
   })); 
  }

  public double[] ParseTextStream(string wrkString)
  {
   // MessageBox.Show(wrkString);
   string[] stringSeparators = new string[] { "," };
   string[] sresult = new string[10];
   double[] result = new double[4];
   sresult = wrkString.Split(stringSeparators, StringSplitOptions.None);
   result[0] = Double.Parse(sresult[1]); //EDM
   result[1] = Double.Parse(sresult[2]);  //HR
   result[2] = Double.Parse(sresult[7]);  //BVP
   result[3] = Double.Parse(sresult[8]); //HRV
   return result;
  }

  private Point NormalizePoint(Point pt)
  {
   Point result = new Point();
   result.X = ((pt.X - xmin) * GraphCanvas.Width / (xmax - xmin));
   result.Y = GraphCanvas.Height - (pt.Y - ymin) * GraphCanvas.Height / (ymax - ymin);
   return result;
  }

  public void chartGrid_SizeChanged(Object sender, SizeChangedEventArgs e)
  {
   if (pl == null) return;
   GraphCanvas.Width = graphGrid.ActualWidth;
   GraphCanvas.Height = graphGrid.ActualHeight;
   GraphCanvas.Children.Clear();
   GraphCanvas.Children.Add(pl);
   // AddChart();
  }

  public Polyline CreateNewPolyLine(ObservableCollection<Point> obdpts)
  {
   Polyline pltemp = new Polyline();
   pltemp.Stroke = Brushes.Red;
   pltemp.StrokeThickness = .5;
   foreach (Point pt in obdpts)
   {
    pltemp.Points.Add(NormalizePoint(pt));  //(NormalizePoint(pt))
   }
   return pltemp;

  }

  private void Window_Loaded(object sender, RoutedEventArgs e)
  {
   Obdatapoints.CollectionChanged += new NotifyCollectionChangedEventHandler(Obdatapoints_CollectionChanged);
   _bw.RunWorkerAsync();
  }
 }
}


这篇关于WPF本机图表控件和持续更新的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆