LaVOZs

The World’s Largest Online Community for Developers

'; winforms - serial port event not firing after opening the form using showDialog() method in c# windows form application - LavOzs.Com

Actually i am receiving data from com serial port to get phone/mobile number while people/customers call to restaurant for order.

First Time serial port listening perfectly and then windows form displying the phone number correctly. To open windows form I have to use this.showdialog() instead of this.show(). Because there few more forms already open behind of the current form.

The problem is happening after fist time showing the dialog, serial port not listening phone call or serial port function on triggering and the the form is not being updated with new caller phone number.

I understand this is happening because of use of showdialog() but i have to use this. I am put down the code i used ..

private void FindCom()
        {

            try
            {
                //Messagebox.show("Called Find Com"); 
                LogFile.WriteLogFile("File:Caller", "Method:FindCom", "--FindCom Called--");
                string COM = RunProcess("FindCOMET.exe"); // Using the autofind to find the unit's
                string[] COMPorts = COM.Split(';'); // Split the AutoFind string into individual ports
                COM = COMPorts[0]; // Select the first COM port 
                // Initialise COM port with all settings.
                serialPort = new SerialPort();
                serialPort.PortName = COM;
                serialPort.BaudRate = 1200;
                serialPort.DataBits = 8;
                serialPort.StopBits = StopBits.One;
                serialPort.Parity = Parity.None;
                serialPort.DataReceived += new SerialDataReceivedEventHandler(this.serialPort_DataReceived);
                serialPort.ReadTimeout = 100; // Required for end of packet Timeout notification
                serialPort.Open();
            }
            catch (Exception ex)
            {
                //MessageBox.Show("Exception1"+ ex.Message.ToString());
                LogFile.WriteLogFile("File:Caller", "Method:FindCom", "EM: " + ex.Message.ToString());
            }
            // Loop until user presses a key then exit
            //System.Console.WriteLine("Press any key to exit");
            //Console.ReadKey();
        }

        // Variables for the data read
        int[] buffer = new int[255];
        int pointer;
        private void serialPort_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
        {
            try
            {
                // Read all the current buffer into the array
                for (int c = 0; c != serialPort.BytesToRead; c++)
                {
                    buffer[pointer] = serialPort.ReadByte();
                    pointer++;
                }
            }
            catch (TimeoutException x)
            {
                try
                {
                   
                    COMET_Data cid = new COMET_Data(buffer);
                    // Output the data or call something within your program here 
                    string mobileNo = cid.getCIDNumber();
                    string telePhone =string.Empty;
                    var getName = string.Empty;
                    if (mobileNo != null)
                    {
                        mobileNo = Regex.Replace(mobileNo, "[^0-9]+", string.Empty);
                       // MessageBox.Show("FullNumber" + mobileNo);
                        if (mobileNo[0] == '9')
                        {
                            mobileNo = mobileNo.Substring(1);
                        }
                        //MessageBox.Show(mobileNo.Substring(0, 2)+" OF =>"+ mobileNo);
                        if (mobileNo.Substring(0,2) == "07")
                        {
                            //mobileNo = mobileNo;
                            txtbxMobileNo.Text = mobileNo;
                            lblMobileNo.Text = mobileNo;
                        }
                        else
                        {
                            
                            telePhone = mobileNo;
                            //MessageBox.Show("telephone:" + telePhone);
                            txtbxTelephone.Text = telePhone;
                            lblMobileNo.Text = telePhone;
                        }
                        getName = cid.getCIDName();
                        
                    }
                    else
                    {
                        lblCustomerName.Text = "Not Available";
                        txtbxMobileNo.Text = "Withheld";
                        lblMobileNo.Text = "Withheld";
                    }


                    //MessageBox.Show(mobileNo); 
                    SaveCommetCaller(mobileNo);
                    // Reset the buffer pointer and buffer
                    buffer = new int[255];
                    pointer = 0;
                    //for (int i = 1; i >= 0; i--)

                    isFormOpen = true;
                    this.ShowDialog();
                    serialPort.DiscardInBuffer();
                    //is_open = false;
                }
                catch (Exception ex)
                {
                    LogFile.WriteLogFile("File:Caller", "Method:DataReceived", "EM: " + ex.Message.ToString());
                }
                //serialPort.DataReceived += new SerialDataReceivedEventHandler(this.serialPort_DataReceived);
            }
            finally
            {
               // serialPort.DataReceived += serialPort_DataReceived;
            }
        }

The ShowDialog() will block your application no matter what. Best result I could achive can be watched here: Dialogs video

First, put your event emitter in separate thread/task and inject the event emitter to the first form:

static class Program
{
    [STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);

        var callReceiver = new CallReceiver();

        var thread = new Thread(callReceiver.WaitForCall);
        thread.Start();

        Application.Run(new Form1(callReceiver));
    }
}

public class CallReceiver
{
    public event EventHandler<int> CallReceived;

    public void WaitForCall()
    {
        var i = 0;
        while (true)
        {
            Thread.Sleep(1000);
            OnCallReceived(i++);//Dummy event emitter
        }
    }
    protected virtual void OnCallReceived(int e)
    {
        CallReceived?.Invoke(this, e);
    }
}

The first form listens to the event of an incoming call and creates a dialog when a call enters. The event emitter is injected to the second dialog as well. Form1.cs:

public partial class Form1 : Form
{
    private readonly CallReceiver _callReceiver;
    private DisplayCallForm _displayCallForm;
    public Form1(CallReceiver callReceiver)
    {
        _callReceiver = callReceiver;
        InitializeComponent();

        _callReceiver.CallReceived += CallReceiverOnCallReceived;

    }

    private void CallReceiverOnCallReceived(object sender, int i)
    {

        this.InvokeIfRequired(() =>
        {
            if (_displayCallForm == null)
            {
                _displayCallForm = new DisplayCallForm(_callReceiver);

                _displayCallForm.Show(this); //give "this" to show() to make sure the 
                                             //new dialog is in foreground.
            }
        });
    }
}

the this.InvokeIfRequired() is to avoid cross-thread problems and looks like this:

static class Invoker
{
    public static void InvokeIfRequired(this Control control, MethodInvoker action)
    {
        if (control.InvokeRequired)
        {
            control.Invoke(action);
        }
        else
        {
            action();
        }
    }
}

DisplayCallForm.cs:

public partial class DisplayCallForm : Form
{
    private readonly CallReceiver _callReceiver;

    public DisplayCallForm(CallReceiver callReceiver)
    {

        InitializeComponent();
        _callReceiver = callReceiver;

        _callReceiver.CallReceived += CallReceiverOnCallReceived;
    }

    private void CallReceiverOnCallReceived(object sender, int i)
    {
        this.InvokeIfRequired(() =>
        {
            label1.Text = i.ToString();
        });
    }
}

Hope this helps.

I had the same issue and solved it surprisingly simple, iam not calling "serialPort1.Close();" after i recieved data but instead in the button for going back to mainpage in my case:

private void button1_Click(object sender, EventArgs e)
{
    serialPort1.Close();  //  <---
    Form1 nextForm = new Form1();
    Hide();
    nextForm.ShowDialog();
    Close();
}   

this allows me to switch between winforms and keep functional serialport1.