2

I am trying to implement a winform application that presents on a line-chart a set of samples (coming form HW device).

I used the INotifyPropertyChanged Interface and bind the chart to the model of the HW device, but it seems that the chart doesn't get updated when the samples are changed at the HW model.

Sorry, if this is too basic (I am more of an embedded guy), but it seems that I am missing the part that connects the INotifyPropertyChanged event to the data binder.

Is there something missing here? or should I implement it differently?

At the WinForm class I wrote the following code to bind the chart to the samples of the HW model The buttons should demonstrate case when the 'ADCSamples' changes:

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
        StreamChart.Series[0].Points.DataBindY(GSWatch.ADCSamples);
    }

    private GSWatchModel GSWatch = new GSWatchModel();

    private void button1_Click(object sender, EventArgs e)
    {
        uint[] muki = new uint[128];
        for (int i = 0; i < 128; i++)
        {
            muki[i] = (uint)(i / 10);
        }

        GSWatch.ADCSamples = muki;
        //StreamChart.Series[0].Points.DataBindY(GSWatch.ADCSamples);   //The chart is only updated if this line is executed
    }

    private void button2_Click(object sender, EventArgs e)
    {
        GSWatch.StartStreamADC();
        //StreamChart.Series[0].Points.DataBindY(GSWatch.ADCSamples);   //The chart is only updated if this line is executed
    }
}

At the HW model I wrote the following code to implement the INotifyPropertyChanged feature:

    public class GSWatchModel : INotifyPropertyChanged
    {
    public event PropertyChangedEventHandler PropertyChanged;
    private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    private uint[] aDCSamples = new uint[128];

    public uint[] ADCSamples
    {
        get
        {
            return aDCSamples;
        }

        set
        {
            aDCSamples = value;
            NotifyPropertyChanged();
        }
    }

    public GSWatchModel()
    {
        CommLink = new GSCommManager();
        for (int i = 0; i < 128; i++)
        {
            aDCSamples[i] = (uint)(i);      //initial values for demo
        }
    }

    uint muki = 0;
    public void StartStreamADC()
    {
        GSPacket StreamRequestPacket = new GSPacket(GSPTypes.Stream);
        CommLink.SendViaGSWatchLink(StreamRequestPacket);

        for (int i = 0; i < 128; i++)
        {
            aDCSamples[i] = (uint)i / 10;   //steps for demonstration
        }
        NotifyPropertyChanged();
        muki += 100;
    }
}
Modi
  • 23
  • 5

2 Answers2

0

ADCSamples doesn't implement IOnNotifyPropertyChanged at all.

You could:

  • Change it to indexer property and implement IOnNotifyPropertyChanged correctly PropertyChanged for indexer property

  • Change it to ObservableCollection which already implements IOnNotifyPropertyChanged:

    public class GSWatchModel : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; private void NotifyPropertyChanged([CallerMemberName] String propertyName = "") { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } }

    private ObservableCollection<uint> aDCSamples = new ObservableCollection<uint>();
    public ObservableCollection<uint> ADCSamples
    {
        get
        {
            return aDCSamples;
        }
    
        set
        {
            aDCSamples = value;
            NotifyPropertyChanged("ADCSamples");
        }
    }
    
    public GSWatchModel()
    {
        CommLink = new GSCommManager();
    
        for (int i = 0; i < 128; i++)
        {
            ADCSamples.Add((uint)(i));      //initial values for demo
        }
    }
    
    uint muki = 0;
    public void StartStreamADC()
    {
        GSPacket StreamRequestPacket = new GSPacket(GSPTypes.Stream);
        CommLink.SendViaGSWatchLink(StreamRequestPacket);
    
        for (int i = 0; i < 128; i++)
        {
            ADCSamples[i] = (uint)i / 10;   //steps for demonstration
        }
    
        muki += 100;
    }
    

    }

    public partial class Form1 : Form { public Form1() { InitializeComponent(); StreamChart.Series[0].Points.DataBindY(GSWatch.ADCSamples); }

    private GSWatchModel GSWatch = new GSWatchModel();
    
    private void button2_Click(object sender, EventArgs e)
    {
        GSWatch.StartStreamADC();
    }
    

    }

Community
  • 1
  • 1
Daniel Luberda
  • 7,374
  • 1
  • 32
  • 40
  • Thank you very much for the tip. I guess I am not implement it correctly. I am not sure I understand correctly how to implement it on my example. could you please elaborate what I am missing at the form part? – Modi Aug 20 '15 at 11:51
  • I updated the example (I don't know why code formating is incorrect) – Daniel Luberda Aug 20 '15 at 15:50
  • Thank you very much for the implementation with ObservableCollection. I have tried it and still it doesn't get updated because the event capture function that @jstreet sugested was missing, and also 'NotifyPropertyChanged("ADCSamples")' was missing in 'StartStreamADC()'. – Modi Aug 23 '15 at 06:34
0

Move StartStreamADC before the binding... see below:

    private void Form1_Load(object sender, EventArgs e)
    {
        GSWatchModel GSWatch = new GSWatchModel();
        GSWatch.StartStreamADC();

        StreamChart.Series[0].Points.DataBindY(GSWatch.ADCSamples);
    }

Result:

enter image description here

In order to get notified, do this:

    private void Form1_Load(object sender, EventArgs e)
    {
        GSWatch = new GSWatchModel();
        GSWatch.StartStreamADC();

        StreamChart.Series[0].Points.DataBindY(GSWatch.ADCSamples);

        GSWatch.PropertyChanged += GSWatch_PropertyChanged;

    }

    private void GSWatch_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        StreamChart.Series[0].Points.DataBindY(GSWatch.ADCSamples);
    }

Also, please change ADCSamples to this:

        public List<uint> ADCSamples = new List<uint>();

It will save you a lot of headache.

jsanalytics
  • 13,058
  • 4
  • 22
  • 43
  • Thank you so much. When I StartStremADC before the binding it does shown on the chart but the chart doesn't change whenever the samples are changed. I probably haven't implemented the IOnNotifyPropertyChanged correctly as daniel-luberda said. Can you please show me how should I implement the IOnNotifyPropertyChanged correctly in this example? – Modi Aug 20 '15 at 11:49
  • You have to call `chart.DataBind()` whenever your data sample changes. Your implementation of `INotifyPropertyChanged` looks correct to me... Only problem is, i normally only use that with WPF applications, not WinForms. In WinForms i normally just call `DataBind()`. – jsanalytics Aug 20 '15 at 12:59
  • Also, you didn't post the code where your sample data is changed, only the initial data load. If you have problems when the data changes, then you have to post that piece of code. – jsanalytics Aug 20 '15 at 13:32
  • The problem is that I can't call 'chart.DataBind()' whenever the samples are changes because they changed at the model and not the form. That is why I wanted to use 'INotifyPropertyChanged ' for the first place. I have updated my question code. I need that whenever 'StartStreamADC()' is called, or whenever the 'ADCSamples' setter is called, the chart will be updated. But it doesn't. – Modi Aug 20 '15 at 14:29
  • Thank you very much. That was exactly what I was missing. – Modi Aug 20 '15 at 15:38
  • Please give it a green check if it solves your problem. – jsanalytics Aug 20 '15 at 15:40
  • This solution still requires you to manually rebind the data external to the chart (which I think re-copies all your data), rather than the chart binding listening for the PropertyChanged event and doing something smarter than a whole copy. – Jacob Nov 22 '16 at 22:36