【发布时间】:2016-12-05 13:14:40
【问题描述】:
我是 c# 新手,有一个简单的项目,我有一个 Form1,它有一个打开按钮 Form2(诊断页面稍后将受密码保护)。
我创建了一个SerialPortClass,你可以猜到它处理所有的串口方法,例如 openport、sendline、isPortOpen 等。
我想要做的是从SerialPortClass 的串口接收一个串行字符串,然后在Form2 的文本框中显示这个字符串。在阅读了本网站和其他网站上的许多帖子后,我尝试以多种方式实现这一目标。
根据我的阅读,使用BackGroundWorker 是最好的方法。所以我复制了示例Microsoft Thread safe example,并在Form2 上有一个按钮以使用BackGroundWorker,以成功显示TextBox 中的文本。但是,当我尝试从 SerialPortClass 运行 BackGroundWorker 时,我得到一个:
抛出异常:SerialTest.exe 中的“System.NullReferenceException” 附加信息:对象引用未设置为对象的实例。
谁能指点我正确的方向?
我知道我实际上正在传递字符串,但只是尝试在另一个类中启动后台工作作为测试
完整的 SerialPort 类:
using System;
using System.IO;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.IO.Ports;
using System.Windows.Forms;
using System.Collections;
using System.Threading;
using System.Reflection;
using UsbLibrary;
namespace SerialTest
{
public class SerialPortClass : Form
{
private static SerialPortClass instance;
private System.IO.Ports.SerialPort serialPort1 = new SerialPort(); // Initilises an instance of COM port
private System.IO.Ports.SerialPort serialPort2 = new SerialPort(); // and another
Form1 form1;
Form2 form2;
internal delegate void SerialDataReceivedEventHandlerDelegate(
object sender, SerialDataReceivedEventArgs e);
delegate void SetTextCallback(string text);
string InputData = String.Empty;
private static SerialPort port;
public SerialPortClass()
{
serialPort1.DataReceived +=
new System.IO.Ports.SerialDataReceivedEventHandler(port_DataReceived_1);
}
public static readonly SerialPortClass _instance = new SerialPortClass();
public ThreadStart ThreadProcSafe { get; private set; }
public bool serialOpen(int port)
{
if (port == 1)
{
if (serialPort1.IsOpen) return true;
else return false;
}
else if (port == 2)
{
if (serialPort2.IsOpen) return true;
else return false;
}
else return false;
}
public void serialSendString(int port, string command)
{
if (port == 1)
{
// If the port is closed, don't try to send a character.
if (!serialPort1.IsOpen) return;
serialPort1.WriteLine(command);
}
else if (port == 2)
{
if (!serialPort2.IsOpen) return;
serialPort2.WriteLine(command);
}
else
{
MessageBox.Show("Invalid port no");
}
}
public void serialSendString1(string command)
{
// If the port is closed, don't try to send a character.
if (serialPort1.IsOpen)
{
serialPort1.WriteLine(command);
}
else
{
MessageBox.Show("port not opening at connect..");
return;
}
}
public void serialSendString2(string command)
{
// If the port is closed, don't try to send a character.
if (serialPort2.IsOpen)
{
serialPort2.WriteLine(command);
}
else
{
MessageBox.Show("port not opening at connect..");
return;
}
}
public void Connect() //SerialTest.Form1 form) //string comPortNo, int baud)
{
serialPort1.PortName = "COM38"; // comPortNo;
serialPort1.BaudRate = 9600; // baud;
if (serialOpen(1))
{
MessageBox.Show("Serial port already open");
return;
}
try
{
serialPort1.Open();
serialPort1.NewLine = "\r";
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
if (serialOpen(1))
{
Console.WriteLine("port open");
}
else
{
MessageBox.Show("port not opening at connect..");
}
}
private void port_DataReceived_1(object sender, SerialDataReceivedEventArgs e)
{
Console.WriteLine("Data recieved");
InputData = serialPort1.ReadExisting();
if (InputData != String.Empty)
{
SetText(InputData);
}
}
public void SetText(string text)
{
Console.WriteLine("set text");
form2.backgroundWorker1.RunWorkerAsync();
}
public void disconnect()
{
//serialPort1.PortName = "COM38";
//serialPort1.BaudRate = 9600;
if (serialOpen(1))
{
serialPort1.Close();
Console.WriteLine("Port closed");
}
else
{
MessageBox.Show("Port not open to close");
}
}
public class SerialErrorReceivedEventArgs : EventArgs
{
//Data to pass to the event
public string LineData { get; private set; }
public SerialErrorReceivedEventArgs(string lineData)
{
this.LineData = lineData;
}
}
}
}
和Form2:
using System;
using System.Threading;
using UsbLibrary;
using log4net;
using SensorTestApp;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using SerialTest;
using System.IO.Ports;
namespace SerialTest
{
public partial class Form2 : Form
{
string comPortNo;
// This delegate enables asynchronous calls for setting
// the text property on a TextBox control.
delegate void SetTextCallback(string text);
// This thread is used to demonstrate both thread-safe and
// unsafe ways to call a Windows Forms control.
public Thread demoThread = null;
// This BackgroundWorker is used to demonstrate the
// preferred way of performing asynchronous operations.
public BackgroundWorker backgroundWorker1;
//private TextBox tBQuery;
private Button setTextUnsafeBtn;
private Button setTextSafeBtn;
private Button setTextBackgroundWorkerBtn;
private System.ComponentModel.IContainer components1 = null;
public static Form2 _instance = new Form2();
public Form2()
{
InitializeComponent();
this.backgroundWorker1 = new BackgroundWorker();
// here you have also to implement the necessary events
// this event will define what the worker is actually supposed to do
this.backgroundWorker1.DoWork += backgroundWorker1_DoWork;
//this.backgroundWorker1.RunWorkerAsync += backgroundWorker1_RunWorkerAsync;
// this event will define what the worker will do when finished
this.backgroundWorker1.RunWorkerCompleted += backgroundWorker1_RunWorkerCompleted;
btnRelay1On.Enabled = false;
btnRelay2On.Enabled = false;
btnRelay3On.Enabled = false;
btnRelay4On.Enabled = false;
btnRelay5On.Enabled = false;
btnRelay1Off.Enabled = false;
btnRelay2Off.Enabled = false;
btnRelay3Off.Enabled = false;
btnRelay4Off.Enabled = false;
btnRelay5Off.Enabled = false;
}
// This event handler creates a thread that calls a
// Windows Forms control in a thread-safe way.
private void button2_Click(
object sender,
EventArgs e)
{
this.demoThread =
new Thread(new ThreadStart(this.ThreadProcSafe));
this.demoThread.Start();
}
// This method is executed on the worker thread and makes
// a thread-safe call on the TextBox control.
public void ThreadProcSafe()
{
this.SetText("This text was set safely.");
}
// This method demonstrates a pattern for making thread-safe
// calls on a Windows Forms control.
//
// If the calling thread is different from the thread that
// created the TextBox control, this method creates a
// SetTextCallback and calls itself asynchronously using the
// Invoke method.
//
// If the calling thread is the same as the thread that created
// the TextBox control, the Text property is set directly.
public void AppendText(String text)
{
if (this.InvokeRequired)
{
this.Invoke(new Action<string>(AppendText), new object[] { text });
return;
}
this.richTextBox1.Text += text;
}
public void SetText(string text)
{
// InvokeRequired required compares the thread ID of the
// calling thread to the thread ID of the creating thread.
// If these threads are different, it returns true.
if (this.tBQuery.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(SetText);
this.Invoke(d, new object[] { text });
Console.WriteLine("different thread, text callback");
}
else
{
Console.WriteLine("same thread, string: %s", text);
this.tBQuery.Text = text;
}
}
// This event handler starts the form's
// BackgroundWorker by calling RunWorkerAsync.
//
// The Text property of the TextBox control is set
// when the BackgroundWorker raises the RunWorkerCompleted
// event.
public void button1_Click(
object sender,
EventArgs e)
{
this.backgroundWorker1.RunWorkerAsync();
}
public void backgroundWorker1_DoWork(object sender,
DoWorkEventArgs e)
{
Console.WriteLine("BackgroundWorker1_Do Work");
}
// This event handler sets the Text property of the TextBox
// control. It is called on the thread that created the
// TextBox control, so the call is thread-safe.
//
// BackgroundWorker is the preferred way to perform asynchronous
// operations.
public void backgroundWorker1_RunWorkerCompleted(
object sender,
RunWorkerCompletedEventArgs e)
{
this.tBQuery.Text =
"This text was set safely by BackgroundWorker.";
}
private void cbComPort_SelectedIndexChanged(object sender, EventArgs e)
{
comPortNo = cbComPort.Text.ToString();
btnOpenCom.Enabled = true;
}
private void btnOpenCom_Click(object sender, EventArgs e)
{
//SerialPortClass.GetInstance().Connect(comPortNo, 9600);
try
{
SerialPortClass._instance.Connect();
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
if (SerialPortClass._instance.serialOpen(1))
{
btnOpenCom.Enabled = false;
btnCloseCom.Enabled = true;
btnRelay1On.Enabled = true;
btnRelay2On.Enabled = true;
btnRelay3On.Enabled = true;
btnRelay4On.Enabled = true;
btnRelay5On.Enabled = true;
btnRelay1Off.Enabled = true;
btnRelay2Off.Enabled = true;
btnRelay3Off.Enabled = true;
btnRelay4Off.Enabled = true;
btnRelay5Off.Enabled = true;
}
else MessageBox.Show("port not open btnOpenCom");
}
private void btnCloseCom_Click(object sender, EventArgs e)
{
try
{
SerialPortClass._instance.disconnect();
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
if (!SerialPortClass._instance.serialOpen(1))
{
btnOpenCom.Enabled = true;
btnCloseCom.Enabled = false;
btnRelay1On.Enabled = false;
btnRelay2On.Enabled = false;
btnRelay3On.Enabled = false;
btnRelay4On.Enabled = false;
btnRelay5On.Enabled = false;
btnRelay1Off.Enabled = false;
btnRelay2Off.Enabled = false;
btnRelay3Off.Enabled = false;
btnRelay4Off.Enabled = false;
btnRelay5Off.Enabled = false;
}
}
private void btnRelay1On_Click(object sender, EventArgs e)
{
SerialPortClass._instance.serialSendString(1, "OH1");
}
private void btnRelay1Off_Click(object sender, EventArgs e)
{
SerialPortClass._instance.serialSendString(1, "OL1");
}
private void btnRelay2On_Click(object sender, EventArgs e)
{
SerialPortClass._instance.serialSendString(1, "OH2");
}
private void btnRelay2Off_Click(object sender, EventArgs e)
{
SerialPortClass._instance.serialSendString(1, "OL2");
}
private void btnRelay3On_Click(object sender, EventArgs e)
{
SerialPortClass._instance.serialSendString(1, "OH3");
}
private void btnRelay3Off_Click(object sender, EventArgs e)
{
SerialPortClass._instance.serialSendString(1, "OL3");
}
private void btnRelay4On_Click(object sender, EventArgs e)
{
SerialPortClass._instance.serialSendString(1, "OH4");
}
private void btnRelay4Off_Click(object sender, EventArgs e)
{
SerialPortClass._instance.serialSendString(1, "OL4");
}
private void btnRelay5On_Click(object sender, EventArgs e)
{
SerialPortClass._instance.serialSendString(1, "OH5");
}
private void btnRelay5Off_Click(object sender, EventArgs e)
{
SerialPortClass._instance.serialSendString(1, "OL5");
}
private void btnQuery_Click(object sender, EventArgs e)
{
//this.BeginInvoke(new SetTextCallback(SetText), new object[] { "hjdfdsfj" });
SerialPortClass._instance.serialSendString(1, "?");
Console.WriteLine("?");
}
}
}
Designer 文件中还有对 BackgroundWorker 的引用,所以我也将其包含在此处:
this.backgroundWorker1 = new System.ComponentModel.BackgroundWorker();
//
// backgroundWorker1
//
this.backgroundWorker1.RunWorkerCompleted += new System.ComponentModel.RunWorkerCompletedEventHandler(this.backgroundWorker1_RunWorkerCompleted);
//private System.ComponentModel.BackgroundWorker backgroundWorker1;
【问题讨论】:
-
你从哪里得到异常?
-
你在哪里初始化
form2?你在哪里初始化backgroundWorker1?null是哪个对象? -
你还没有为
backgroundWorker1设置动作 -
后台工作人员实际上应该做什么?我没有看到任何与之相关的
SerialPort操作 -
您是否尝试过将 BackgroundWorker 组件添加到表单(从工具箱中选择)而不是声明变量。
标签: c# backgroundworker