Search code examples
c#xamlmauisyncfusioninotifypropertychanged

How to make Syncfusion gauge "NeedlePointer" value update on Property Change Event?


I am reading data from a LoRa scanner utilizing SerialPort that gets among other things, the signal strength (RSSI) that ranges between -10 and -110. I want the gauge to update automatically every time a new RSSI value is read.

I have created a serialPortConn class where I connect to the scanner and read the data using a function named SerialPort_DataReceived:

public void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
    {  
        try
        {
            while (serialPort.BytesToRead > 0)
            {
                 string DataIn = serialPort.ReadLine();
                 Debug.WriteLine("Data received from the scanner: " + DataIn);

                // Process the received data and extract the fields
                    Network data = ProcessReceivedData(DataIn);

                 MainThread.BeginInvokeOnMainThread(() =>
                    {
                        // Check if the data name is not empty or null
                        if (!string.IsNullOrEmpty(data.Name))
                        {
                            // Find the existing network with the same name, if it exists
                            Network existingNetwork = NetworkNames.FirstOrDefault(network => network.Name == data.Name);

                            if (existingNetwork != null)
                            {
                                // Add the RSSI value to the existing network's RSSIList
                        
                                // NetworkNames.Add(new Network { RSSI = data.RSSI });
                                // strength = data.RSSI;
                                Strength = data.RSSI;
                                existingNetwork.RSSI = data.RSSI;
                                existingNetwork.Name = data.Name;

                                Debug.WriteLine("strength: " + strength);

                            }
                            else
                            {
                                // Create a new network with the name and initialize its RSSIList 
                                NetworkNames.Add(new Network { Name = data.Name, RSSI = data.RSSI });

                                // strength = data.RSSI;
                                Strength = data.RSSI;
                            }

                            // Print the network name and its RSSIList for debugging purposes
                            foreach (Network network in NetworkNames)
                            {
                                Debug.WriteLine("NetworkName: " + network.Name + " " + network.RSSI);
                            }

                        }
                    });
            }
        }
        catch (OperationCanceledException)
        {
            // Handle the cancellation if needed
            Debug.WriteLine("Reading data from the scanner was canceled.");
        }
        catch (Exception ex)
        {
            // Handle other exceptions
            Debug.WriteLine($"Failed to read data from the scanner: {ex.Message}");
        }
        
    }

I am savig the new RSSI value to a strength property defined at the beginning of the SerialPortConn as follow:

public class SerialPortConn : INotifyPropertyChanged
    { 
        //public ObservableCollection<Network> NetworkNames { get; set; }
        private SerialPort serialPort;
        Network networkNames = new Network();
        public ObservableCollection<Network> NetworkNames { get; set; } = new ObservableCollection<Network>();
        private int strength;

        public int Strength
        {
            get { return strength; }
            //get => strength;
            set
            {
                if (strength != value)
                {
                    strength = value;
                    OnPropertyChanged(nameof(Strength));
                    //OnPropertyChanged();
                }
            }
        }
        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged(string propertyName)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }

In the content page code behind, I am trying to assign the Strength property to the NeedlePointer value as follow:

namespace Scanner_MAUI.Pages;

public partial class HistoricalData : ContentPage, INotifyPropertyChanged
{
    //public ObservableCollection<Network> NetworkNames { get; set; }
    private SerialPortConn scannerConn;
    public HistoricalData()
    {
        InitializeComponent();
        needlePointer.Value = scannerConn.Strength;
        Number.Text = scannerConn.Strength.ToString();
        scannerConn.PropertyChanged += ScannerConn_PropertyChanged;

      //..More Code
    }

    private void ScannerConn_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
    {
        if (e.PropertyName == nameof(scannerConn.Strength))
        {
            //MainThread.BeginInvokeOnMainThread(() =>
            //{
                new HistoricalData();
                needlePointer.Value = scannerConn.Strength;
                Number.Text = scannerConn.Strength.ToString();
                Debug.WriteLine("test1 " +  needlePointer.Value);
                Debug.WriteLine("test2 " + Number.Text);
            //});
        }
    }

But the guage value doesn't change. Note I did a similar approach for a list that shows Network names by adding in the code behind the following line: NetworkListView.ItemsSource = scannerConn.NetworkNames; The difference is that the names are saved in an ObservableCollection. And this shows the new names in the listView while the scan is running.

Finally this is the xaml:

 <Frame Grid.Row="1">
            <Grid>
                <gauge:SfRadialGauge x:Name="radialGauge">
                <!-- more stuff -->
                 <gauge:RadialAxis.Pointers>
                     <gauge:NeedlePointer x:Name="needlePointer"  />
                  </gauge:RadialAxis.Pointers>
                  <gauge:RadialAxis.Annotations>
                  <gauge:GaugeAnnotation x:Name="annotation" DirectionUnit="Angle" DirectionValue="90" PositionFactor="0.5">
                     <gauge:GaugeAnnotation.Content>
                         <Label x:Name="Number" FontSize="25" FontAttributes="Bold" TextColor="Black"/>
                      </gauge:GaugeAnnotation.Content>
                        </gauge:GaugeAnnotation>
                       <!-- more stuff -->

Update!!!! this is the console out put of the data I get:

strength: -24
15:24:50:061    existingNetwork: device_1_dummy -24
15:24:50:061    NetworkName: device_1_dummy -24
15:24:50:061    NetworkName: device_1_dummy -24
15:24:50:061    NetworkName: device_1_dummy -25
15:24:52:309    Data received from the scanner: message: datastearm, name: b'device_1_dummy', type: LoRaRAW, lat: None, lon: None, rssi: -25, snr: 6.0, time: (2023, 6, 15, 20, 32, 39, 775777, None)

strength: -25
....and so on

The negative number is the RSSI value I am after. With the dummy data that I am getting there is only one network name however the RSSI value changes all the time. I tried using on click and on Item selected events. With These I only get one RSSI value and it shows on the gauge. PLEASE NOT I AM A NOOBIE STILL :)


Solution

  • in SerialPort_DataReceived you are setting strength which is a private field, not Strength which is a public property. The latter fires a PropertyChanged event, the former does not