在 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 的功能。
实际上我正在从 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 的功能。