Click here to Skip to main content
15,887,302 members
Please Sign up or sign in to vote.
1.00/5 (1 vote)
See more:
Hello guys,

I need help.

I'm trying to develope a modbus poll program to read an energy metter. The thing is that I'm using a WF program that I found and trying to convert it to WPF.

Please take a look at it:

C#
<pre>using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Timers;
using System.IO.Ports;
using Modbus_Poll_CS;
using WPF_Modbus;
using System.Windows.Threading;
using System.Threading.Tasks;
using System.Threading;


namespace WPF_Modbus
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        //delegate void UpdateThread(int state);
        //Thread th1;

        modbus mb = new modbus();
        SerialPort sp = new SerialPort();
        System.Timers.Timer timer = new System.Timers.Timer();
        string dataType;
        bool isPolling = false;
        int pollCount;

        #region GUI Delegate Declarations
        public delegate void GUIDelegate(string paramString);
        public delegate void GUIClear();
        public delegate void GUIStatus(string paramString);
        #endregion

        public MainWindow()
        {
            InitializeComponent();
            LoadListboxes();
            timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);

        }

        #region Load Listboxes
        private void LoadListboxes()
        {
            //Three to load - ports, baudrates, datetype.  Also set default textbox values:
            //1) Available Ports:
            string[] ports = SerialPort.GetPortNames();

            foreach (string port in ports)
            {
                lstPorts.Items.Add(port);
            }

            lstPorts.SelectedIndex = 0;

            //2) Baudrates:
            string[] baudrates = { "9600", "19200", "38400", "57600", "115200", "230400" };

            foreach (string baudrate in baudrates)
            {
                lstBaudrate.Items.Add(baudrate);
            }

            lstBaudrate.SelectedIndex = 0;

            //3) Datatype:
            string[] dataTypes = { "Float", "Hexadecimal", "Decimal", "Reverse" };

            foreach (string dataType in dataTypes)
            {
                lstDataType.Items.Add(dataType);
            }

            lstDataType.SelectedIndex = 0;

            //Textbox defaults:
            txtRegisterQty.Text = "20";
            txtSampleRate.Text = "1000";
            txtSlaveID.Text = "1";
            txtStartAddr.Text = "1001";
        }
        #endregion

        #region Delegate Functions
        public void DoGUIClear()
        {
            if (!Application.Current.Dispatcher.CheckAccess())
            {
                GUIClear delegateMethod = new GUIClear(this.DoGUIClear);
                Dispatcher.Invoke(delegateMethod);
            }
            else
                this.lstRegisterValues.Items.Clear();
        }
        public void DoGUIStatus(string paramString)
        {
            //if (this.InvokeRequired)
            if (!Application.Current.Dispatcher.CheckAccess())
            {
                GUIStatus delegateMethod = new GUIStatus(this.DoGUIStatus);

                Dispatcher.Invoke(delegateMethod, new object[] { paramString });
            }
            else
                this.lblStatus.Content = paramString;
        }
        public void DoGUIUpdate(string paramString)
        {

            //if (this.InvokeRequired)

            if (!Application.Current.Dispatcher.CheckAccess())
            {
                GUIDelegate delegateMethod = new GUIDelegate(this.DoGUIUpdate);
                Dispatcher.Invoke(delegateMethod, new object[] { paramString });
            }
            else
                this.lstRegisterValues.Items.Add(paramString);
        }
        #endregion

        #region Timer Elapsed Event Handler
        void timer_Elapsed(object sender, ElapsedEventArgs e)
        {
            PollFunction();
        }
        #endregion

        #region Start and Stop Procedures
        private void StartPoll()
        {
            pollCount = 0;

            //Open COM port using provided settings:
            if (mb.Open(lstPorts.SelectedItem.ToString(), Convert.ToInt32(lstBaudrate.SelectedItem.ToString()), 8, Parity.None, StopBits.One))
            {
                //Disable double starts:
                btnStart.IsEnabled = false;
                dataType = lstDataType.SelectedItem.ToString();

                //Set polling flag:
                isPolling = true;
                //Start timer using provided values:
                timer.AutoReset = true;
                if (txtSampleRate.Text != "")
                    timer.Interval = Convert.ToDouble(txtSampleRate.Text);
                else
                    timer.Interval = 1000;
                    timer.Start();
            }

            lblStatus.Content = mb.modbusStatus;
        }
        private void StopPoll()
        {
            //Stop timer and close COM port:
            isPolling = false;
            timer.Stop();
            mb.Close();

            btnStart.IsEnabled = true;

            lblStatus.Content = mb.modbusStatus;
        }
        private void btnStart_Click(object sender, EventArgs e)
        {

            StartPoll();
        }
        private void btnStop_Click(object sender, EventArgs e)
        {
            StopPoll();
        }
        #endregion

        #region Poll Function
        private void PollFunction()
        {



            //Update GUI:
            DoGUIClear();
            //MessageBox.Show("ho");
            pollCount++;
            DoGUIStatus("Poll count: " + pollCount.ToString());

            //Create array to accept read values:

            short[] values = new short[Convert.ToInt32(20)];
            ushort pollStart;
            ushort pollLength;


            if (txtStartAddr.Text != "")
                pollStart = Convert.ToUInt16(txtSampleRate.Text);
            else
                pollStart = 0;

            if (txtRegisterQty.Text != "")
                pollLength = Convert.ToUInt16(20);
            else
                pollLength = 20;

            //Read registers and display data in desired format:
            try
            {
                while (!mb.SendFc3(Convert.ToByte(txtSlaveID.Text), pollStart, pollLength, ref values)) ;

            }
            catch (Exception err)
            {
                DoGUIStatus("Error in modbus read: " + err.Message);
            }

            string itemString;

            switch (dataType)
            {
                case "Decimal":
                    for (int i = 0; i < pollLength; i++)
                    {
                        itemString = "[" + Convert.ToString(pollStart + i + 40001) + "] , MB[" +
                            Convert.ToString(pollStart + i) + "] = " + values[i].ToString();
                        DoGUIUpdate(itemString);
                    }
                    break;
                case "Hexadecimal":
                    for (int i = 0; i < pollLength; i++)
                    {
                        itemString = "[" + Convert.ToString(pollStart + i + 40001) + "] , MB[" +
                            Convert.ToString(pollStart + i) + "] = " + values[i].ToString("X");
                        DoGUIUpdate(itemString);
                    }
                    break;
                case "Float":
                    for (int i = 0; i < (pollLength / 2); i++)
                    {
                        int intValue = (int)values[2 * i];
                        intValue <<= 16;
                        intValue += (int)values[2 * i + 1];
                        itemString = "[" + Convert.ToString(pollStart + 2 * i + 40001) + "] , MB[" +
                            Convert.ToString(pollStart + 2 * i) + "] = " +
                            (BitConverter.ToSingle(BitConverter.GetBytes(intValue), 0)).ToString();
                        DoGUIUpdate(itemString);
                    }
                    break;
                case "Reverse":
                    for (int i = 0; i < (pollLength / 2); i++)
                    {
                        int intValue = (int)values[2 * i + 1];
                        intValue <<= 16;
                        intValue += (int)values[2 * i];
                        itemString = "[" + Convert.ToString(pollStart + 2 * i + 40001) + "] , MB[" +
                            Convert.ToString(pollStart + 2 * i) + "] = " +
                            (BitConverter.ToSingle(BitConverter.GetBytes(intValue), 0)).ToString();
                        DoGUIUpdate(itemString);
                    }
                    break;
            }
        }
        #endregion

        #region Data Type Event Handler
        private void lstDataType_SelectionChanged(object sender, EventArgs e)
        {
            //restart the data poll if datatype is changed during the process:
            if (isPolling)
            {
                StopPoll();
                dataType = lstDataType.SelectedItem.ToString();
                StartPoll();
            }
        }


        #endregion


    }
}



I'm having this:
'The calling thread cannot access this object because a different thread owns it.'

on this line:
if (txtStartAddr.Text != "")


What I have tried:

I have multiple lines similar to the one that detects the exception that produce the same result.

I read a lot about Dispatch commands and further but I couldn't achieve anything.

Please help me
Thank you
Posted
Updated 29-Jan-21 6:04am

 
Share this answer
 
Hello guys,

I already solved it!!


I just had to put some lines between this:

this.Dispatcher.Invoke(() =>
{
 // (CODE)
});




Just for being clear, I'll put the complete program below, you can use (CTRL + F) to find the place where I put the sentences:

<pre>using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Timers;
using System.IO.Ports;
using Modbus_Poll_CS;
using WPF_Modbus;
using System.Windows.Threading;
using System.Threading.Tasks;
using System.Threading;






namespace WPF_Modbus
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        //delegate void UpdateThread(int state);
        //Thread th1;

        modbus mb = new modbus();
        SerialPort sp = new SerialPort();
        System.Timers.Timer timer = new System.Timers.Timer();
        string dataType;
        bool isPolling = false;
        int pollCount;

        #region GUI Delegate Declarations
        public delegate void GUIDelegate(string paramString);
        public delegate void GUIClear();
        public delegate void GUIStatus(string paramString);
        #endregion

        public MainWindow()
        {
            InitializeComponent();
            LoadListboxes();
            timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);

        }

        #region Load Listboxes
        private void LoadListboxes()
        {
            //Three to load - ports, baudrates, datetype.  Also set default textbox values:
            //1) Available Ports:
            string[] ports = SerialPort.GetPortNames();

            foreach (string port in ports)
            {
                lstPorts.Items.Add(port);
            }

            lstPorts.SelectedIndex = 0;

            //2) Baudrates:
            string[] baudrates = { "9600", "19200", "38400", "57600", "115200", "230400" };

            foreach (string baudrate in baudrates)
            {
                lstBaudrate.Items.Add(baudrate);
            }

            lstBaudrate.SelectedIndex = 0;

            //3) Datatype:
            string[] dataTypes = { "Float", "Hexadecimal", "Decimal", "Reverse" };

            foreach (string dataType in dataTypes)
            {
                lstDataType.Items.Add(dataType);
            }

            lstDataType.SelectedIndex = 0;

            //Textbox defaults:
            txtRegisterQty.Text = "20";
            txtSampleRate.Text = "1000";
            txtSlaveID.Text = "1";
            txtStartAddr.Text = "1001";
        }
        #endregion

        #region Delegate Functions
        public void DoGUIClear()
        {
            if (!Application.Current.Dispatcher.CheckAccess())
            {
                GUIClear delegateMethod = new GUIClear(this.DoGUIClear);
                Dispatcher.Invoke(delegateMethod);
            }
            else
                this.lstRegisterValues.Items.Clear();
        }
        public void DoGUIStatus(string paramString)
        {
            //if (this.InvokeRequired)
            if (!Application.Current.Dispatcher.CheckAccess())
            {
                GUIStatus delegateMethod = new GUIStatus(this.DoGUIStatus);

                Dispatcher.Invoke(delegateMethod, new object[] { paramString });
            }
            else
                this.lblStatus.Content = paramString;
        }
        public void DoGUIUpdate(string paramString)
        {

            //if (this.InvokeRequired)

            if (!Application.Current.Dispatcher.CheckAccess())
            {
                GUIDelegate delegateMethod = new GUIDelegate(this.DoGUIUpdate);
                Dispatcher.Invoke(delegateMethod, new object[] { paramString });
            }
            else
                this.lstRegisterValues.Items.Add(paramString);
        }
        #endregion

        #region Timer Elapsed Event Handler
        void timer_Elapsed(object sender, ElapsedEventArgs e)
        {
            PollFunction();
        }
        #endregion

        #region Start and Stop Procedures
        private void StartPoll()
        {
            pollCount = 0;

            //Open COM port using provided settings:
            if (mb.Open(lstPorts.SelectedItem.ToString(), Convert.ToInt32(lstBaudrate.SelectedItem.ToString()), 8, Parity.None, StopBits.One))
            {
                //Disable double starts:
                btnStart.IsEnabled = false;
                dataType = lstDataType.SelectedItem.ToString();

                //Set polling flag:
                isPolling = true;
                //Start timer using provided values:
                timer.AutoReset = true;
                if (txtSampleRate.Text != "")
                    timer.Interval = Convert.ToDouble(txtSampleRate.Text);
                else
                    timer.Interval = 1000;
                    timer.Start();
            }

            lblStatus.Content = mb.modbusStatus;
        }
        private void StopPoll()
        {
            //Stop timer and close COM port:
            isPolling = false;
            timer.Stop();
            mb.Close();

            btnStart.IsEnabled = true;

            lblStatus.Content = mb.modbusStatus;
        }
        private void btnStart_Click(object sender, EventArgs e)
        {

            StartPoll();
        }
        private void btnStop_Click(object sender, EventArgs e)
        {
            StopPoll();
        }
        #endregion

        #region Poll Function
        private void PollFunction()
        {



            //Update GUI:
            DoGUIClear();
            //MessageBox.Show("ho");
            pollCount++;
            DoGUIStatus("Poll count: " + pollCount.ToString());

            //Create array to accept read values:

            short[] values = new short[Convert.ToInt32(20)];
            ushort pollStart;
            ushort pollLength;

            this.Dispatcher.Invoke(() =>
            {
                if (txtStartAddr.Text != "")
                    pollStart = Convert.ToUInt16(txtSampleRate.Text);
                else
                    pollStart = 0;

                if (txtRegisterQty.Text != "")
                    pollLength = Convert.ToUInt16(20);
                else
                    pollLength = 20;

                //Read registers and display data in desired format:
                try
                {
                    while (!mb.SendFc3(Convert.ToByte(txtSlaveID.Text), pollStart, pollLength, ref values)) ;

                }
                catch (Exception err)
                {
                    DoGUIStatus("Error in modbus read: " + err.Message);
                }

                string itemString;

                switch (dataType)
                {
                    case "Decimal":
                        for (int i = 0; i < pollLength; i++)
                        {
                            itemString = "[" + Convert.ToString(pollStart + i + 40001) + "] , MB[" +
                                Convert.ToString(pollStart + i) + "] = " + values[i].ToString();
                            DoGUIUpdate(itemString);
                        }
                        break;
                    case "Hexadecimal":
                        for (int i = 0; i < pollLength; i++)
                        {
                            itemString = "[" + Convert.ToString(pollStart + i + 40001) + "] , MB[" +
                                Convert.ToString(pollStart + i) + "] = " + values[i].ToString("X");
                            DoGUIUpdate(itemString);
                        }
                        break;
                    case "Float":
                        for (int i = 0; i < (pollLength / 2); i++)
                        {
                            int intValue = (int)values[2 * i];
                            intValue <<= 16;
                            intValue += (int)values[2 * i + 1];
                            itemString = "[" + Convert.ToString(pollStart + 2 * i + 40001) + "] , MB[" +
                                Convert.ToString(pollStart + 2 * i) + "] = " +
                                (BitConverter.ToSingle(BitConverter.GetBytes(intValue), 0)).ToString();
                            DoGUIUpdate(itemString);
                        }
                        break;
                    case "Reverse":
                        for (int i = 0; i < (pollLength / 2); i++)
                        {
                            int intValue = (int)values[2 * i + 1];
                            intValue <<= 16;
                            intValue += (int)values[2 * i];
                            itemString = "[" + Convert.ToString(pollStart + 2 * i + 40001) + "] , MB[" +
                                Convert.ToString(pollStart + 2 * i) + "] = " +
                                (BitConverter.ToSingle(BitConverter.GetBytes(intValue), 0)).ToString();
                            DoGUIUpdate(itemString);
                        }
                        break;
                }
            });
            
        }
        #endregion

        #region Data Type Event Handler
        private void lstDataType_SelectionChanged(object sender, EventArgs e)
        {
            //restart the data poll if datatype is changed during the process:
            if (isPolling)
            {
                StopPoll();
                dataType = lstDataType.SelectedItem.ToString();
                StartPoll();
            }
        }


        #endregion


    }
}


Thank you very much
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900