在 c# windows 表单应用程序中使用 showDialog() 方法打开表单后串口事件未触发

serial port event not firing after opening the form using showDialog() method in c# windows form application

实际上我正在从 com 串行端口接收数据以获取 phone/mobile 号码,同时 people/customers 打电话给餐厅订购。

第一次串口完美监听,然后 windows 正确显示 phone 号码。要打开 windows 表单,我必须使用 this.showdialog() 而不是 this.show()。因为在当前表格后面已经打开了几个表格。

问题发生在第一次显示对话框后,串口未监听 phone 调用或串口功能触发,并且表格未使用新的呼叫者 phone 号码更新。

我知道这是因为使用了 showdialog() 而发生的,但我必须使用它。我放下了我使用的代码..

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;
            }
        }

我想在表单仍然打开时使用 showdialog() 方法从串行端口获取数据,而无需用户 activity 关闭或隐藏表单。

无论如何,ShowDialog() 都会阻止您的应用程序。 可以在这里观看我能达到的最佳结果:Dialogs video

首先,将您的事件发射器放在单独的 thread/task 中,并将事件发射器注入第一种形式:

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);
    }
}

第一种形式监听来电事件,并在来电时创建对话。事件发射器也被注入到第二个对话框中。 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.
            }
        });
    }
}

this.InvokeIfRequired() 是为了避免跨线程问题,看起来像这样:

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();
        });
    }
}

希望这对您有所帮助。

我遇到了同样的问题并解决了它非常简单,在我收到数据后我没有调用 "serialPort1.Close();" 而是在我的例子中返回主页的按钮中:

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

这允许我在 winforms 之间切换并保持 serialport1 的功能。