c#文本框,不同类,backgroundWorker

时间:2016-12-05 13:14:40

标签: c# backgroundworker

我是c#的新手并且有一个简单的项目,我有一个Form1,其中有一个按钮可以打开Form2(诊断页面稍后会受到密码保护)。 我创建了一个SerialPortClass,您可以猜测它可以处理所有串口方法,例如openport,sendline,isPortOpen等。 我想要做的是从SerialPortClass的串口接收一个串行字符串,然后在Form2的文本框中显示该字符串。在阅读了本网站和其他网站上的许多帖子后,我试图通过多种方式实现这一目标。 根据我的阅读,使用BackGroundWorker是最好的方法。因此,我复制了示例Microsoft Thread safe example,并在Form2上设置了一个按钮,以使用BackGroundWorker成功显示TextBox中的文字。但是,当我尝试从SerialPortClass运行BackGroundWorker时,我得到了一个:

  

抛出异常:' System.NullReferenceException'在SerialTest.exe中   附加信息:对象引用未设置为对象的实例。

有人能指出我正确的方向吗?

我知道我实际上已经传递了字符串,但只是尝试在其他类中启动后台作为测试

Full SerialPortClass:

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;

2 个答案:

答案 0 :(得分:0)

问题出在这里。

form2.backgroundWorker1.RunWorkerAsync();

您已创建backgroundwoker但未向其注册任何方法/代理。

通过在form2

的构造函数中添加它来分配它
this.backgroundWorker1.DoWork += backgroundWorker1_DoWork; //not found in snippet
this.backgroundWorker1.RunWorkerCompleted +=backgroundWorker1_RunWorkerCompleted;

另外,正如Mong-Zhu所提到的,你需要在form2中初始化这样的Backgroundworker。

this.backgroundWorker1 = new BackGroundWorker();

另外,我个人认为打电话给不同形式的背景工作者不是一个好主意。

答案 1 :(得分:0)

您对BackgroundWorker的使用似乎不完整。您可以将它与Designer一起使用,这更容易,或者在代码隐藏中使用。

要与设计人员一起使用,请将backgroundWorker对象拖放到组件托盘上。然后单击新创建的BackgroundWorker1对象。转到属性托盘并选择事件的闪电。有3个事件,您需要的两个是DoWork和RunWorkerCompleted。双击两者以生成方法。

您的代码段中显示您缺少DoWork部分,并且实际上没有实例化BackGroundWorker对象。它的流动方式是:BackgroundWorker被声明并初始化。当您需要进行异步调用时,您将引发.RunWorkerAsync事件。 RunWorkerAsync事件将进入您的DoWork事件处理程序。这是您为异步工作的代码放置的地方。一旦此DoWork事件过期,就会调用RunWorkercompleted事件。一旦此RunWorkerCompleted事件到期,新线程也将过期。

如果您尝试在与创建它的线程不同的线程中更改设计器组件(即从BackgroundWorker的DoWork事件处理程序内部设置按钮文本),则必须确保使用.InvokeRequired,如看来你已经开始了。

如果你从form2之外调用这个backgroundworker,请确保你将form2的句柄提供给该类。从片段中不清楚是否实例化了一个新的。一种简单的方法是在Serialization类中为Form2创建一个私有字段,以及一个方法,比如AttachForm(Form f),然后从Form2调用该方法,并将 let firstObservable$ = Observable.from([1, 2, 3, 4]) .zip(Observable.interval(50), (a, b) => { return a; }); let secondObservable$ = Observable.from([5, 6]) .zip( Observable.interval(70), (a, b) => { return a; }); firstObservable$ .withLatestFrom(secondObservable$, (f, s) => ({ a: f, b: s })) .subscribe(x => { console.log('result: ', x); }); 作为参数传递。