first of all I describe my objective I want to achive. I want to visualise a continuous data stream (maximum 1000 values per second but could be reduced). This data stream should be visualised as a chart - being more precise it's a visualisation of an ECG among other things.
My first idea was using polyline and bind it to a point collection. The problem here is that nothing is shown on the UI. Perhaps it's a wrong aproach for this task. Better ideas are welcomed. Here ist my code so far. First the View:
<Canvas>
<Polyline Points="{Binding Points}" Stroke="Red" StrokeThickness="2" />
</Canvas>
For the sake of simplicity I use the code-behind even though I use the MVVM-pattern. That's also the reason why I want to use the binding and not just the name of the polyline and add the values.
public partial class MainWindow : Window
{
private short[] data = new short[]{ 10,30,50,70,90,110,130,150,170,190,210 };
private short[] data1 = new short[] { 15,14,16,13,17,12,18,11,19,10,24 };
public MainWindow()
{
InitializeComponent();
for (int i = 0; i < data.Length; i++)
{
Points.Add(new Point(data[i], data1[i]));
}
}
private PointCollection _points = new PointCollection();
public PointCollection Points
{
get { return _points; }
}
}
I know that is no good coding style but for first tests its enough for me. I use array data for x-values and data1 for y-values. Can anyone tell me whats wrong with that binding? What's to be done for a continuous update of the view, whenever new values occur?
Thanks for your help in advance.
[Updated new version] The view:
<Window.Resources>
<my:PointCollectionConverter x:Key="myPointsConverter"/>
</Window.Resources>
<Grid Name="grid">
<Polyline x:Name="ekglineI" Points="{Binding Points, Converter={StaticResource myPointsConverter}}" Stroke="Red" StrokeThickness="2" />
<Button Content="Button" Click="button1_Click" />
</Grid>
The code-behind which draws a polyline on startup and later on when a button is clicked.
public partial class MainWindow : Window, INotifyPropertyChanged
{
private short[] data = new short[] { 10, 30, 50, 70, 90, 110, 130, 150, 170, 190, 210 };
private short[] data2 = new short[] { 230, 250, 270, 290, 300, 310, 330, 350, 370, 390, 410 };
private short[] data1 = new short[] { 15, 14, 16, 13, 17, 12, 18, 11, 19, 10, 24 };
public MainWindow() { InitializeComponent(); grid.DataContext = this; for (int i = 0; i < data.Length; i++) { Points.Add(new Point(data[i], data1[i])); } } public event PropertyChangedEventHandler PropertyChanged; private ObservableCollection _points = new ObservableCollection(); public ObservableCollection Points { get { return _points; } }
private void button1_Click(object sender, RoutedEventArgs e)
{
for (int i = 0; i < data2.Length; i++)
{
Points.Add(new Point(data2[i], data1[i]));
}
PropertyChanged(this, new PropertyChangedEventArgs("Points"));
}
Now what I want to do is getting rid of this line: grid.DataContext = this;
so that I can use my MVVM or is there another possibility?
In order to bind the Polyline Points attribute to your viewmodel successfully (i.e. to have it update when the bound PointCollection changes), you should avoid changing the PointCollection as a collection (Clear, Add, etc). The Polyline will not notice that, even binding to an ObservableCollection of Points with a custom converter will not help.
Instead, you should consider your PointCollection as a property: set it with a newly created PointCollection, and fire a NotifyPropertyChanged event:
private PointCollection points = new PointCollection();
public PointCollection Points
{
get { return points; }
set
{
points = value;
NotifyPropertyChanged("Points");
}
}
public void SomeUpdateFunc()
{
PointCollection pc = new PointCollection();
// Do some adding: pc.Add(new Point(x, y)); etc
this.Points = pc; // set via the setter, so the notification will fire
}
Now the Polyline should be updated properly, good luck!